Replace the per-approver add/remove model with a quorum-based approval system. Documents now have default approvers that are pre-populated when requesting approval, and the publish dialog lets users adjust the list before submitting. Key changes: - Add PENDING_APPROVAL document version status with dedicated transitions - Introduce approval quorums with request/approve/reject/void lifecycle - Add default approvers per document (stored in document_default_approvers) with MERGE-based upsert for efficient sync - Add NoDuplicates validator for slice fields - Split ALTER TYPE ADD VALUE migrations into separate files (required by PostgreSQL when run inside transactions) - Use VOIDED consistently for both quorum status and decision state enums - Expose void/approve/reject through GraphQL and MCP, with e2e tests - Add approval management UI: publish dialog with approver selection, approval list with void support, and external approve/reject page Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
12350 lines
441 KiB
Go
12350 lines
441 KiB
Go
package console_v1
|
|
|
|
// This file will be automatically regenerated based on the schema, any resolver
|
|
// implementations
|
|
// will be copied through when generating and any unknown code will be moved to the end.
|
|
// Code generated by github.com/99designs/gqlgen version v0.17.87
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
pgx "github.com/jackc/pgx/v5"
|
|
"github.com/vikstrous/dataloadgen"
|
|
"go.gearno.de/kit/log"
|
|
"go.probo.inc/probo/pkg/accessreview"
|
|
"go.probo.inc/probo/pkg/accessreview/drivers"
|
|
"go.probo.inc/probo/pkg/connector"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
"go.probo.inc/probo/pkg/gid"
|
|
"go.probo.inc/probo/pkg/iam"
|
|
"go.probo.inc/probo/pkg/mailman"
|
|
"go.probo.inc/probo/pkg/page"
|
|
"go.probo.inc/probo/pkg/probo"
|
|
"go.probo.inc/probo/pkg/server/api/authn"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
|
"go.probo.inc/probo/pkg/server/gqlutils"
|
|
"go.probo.inc/probo/pkg/server/gqlutils/types/cursor"
|
|
"go.probo.inc/probo/pkg/slack"
|
|
"go.probo.inc/probo/pkg/validator"
|
|
)
|
|
|
|
// Campaign is the resolver for the campaign field.
|
|
func (r *accessEntryResolver) Campaign(ctx context.Context, obj *types.AccessEntry) (*types.AccessReviewCampaign, error) {
|
|
if err := r.authorize(ctx, obj.Campaign.ID, probo.ActionAccessReviewCampaignGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.Campaign.ID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Get(ctx, obj.Campaign.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot get access review campaign: %w", err))
|
|
}
|
|
|
|
return types.NewAccessReviewCampaign(campaign), nil
|
|
}
|
|
|
|
// AccessSource is the resolver for the accessSource field.
|
|
func (r *accessEntryResolver) AccessSource(ctx context.Context, obj *types.AccessEntry) (*types.AccessSource, error) {
|
|
if err := r.authorize(ctx, obj.AccessSource.ID, probo.ActionAccessSourceGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.AccessSource.ID)
|
|
|
|
source, err := r.accessReview.Sources(scope).Get(ctx, obj.AccessSource.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot get access source: %w", err))
|
|
}
|
|
|
|
return types.NewAccessSource(source), nil
|
|
}
|
|
|
|
// DecisionHistory is the resolver for the decisionHistory field.
|
|
func (r *accessEntryResolver) DecisionHistory(ctx context.Context, obj *types.AccessEntry) ([]*types.AccessEntryDecisionHistoryEntry, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessEntryGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
histories, err := r.accessReview.Entries(scope).DecisionHistory(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get decision history: %w", err))
|
|
}
|
|
|
|
result := make([]*types.AccessEntryDecisionHistoryEntry, len(histories))
|
|
for i, h := range histories {
|
|
result[i] = types.NewAccessEntryDecisionHistoryEntry(h)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessEntryResolver) Permission(ctx context.Context, obj *types.AccessEntry, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessEntryConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessEntryConnection) (int, error) {
|
|
scope := coredata.NewScopeFromObjectID(obj.ParentID)
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *accessReviewCampaignResolver:
|
|
if obj.SourceID != nil {
|
|
count, err := r.accessReview.Entries(scope).CountForCampaignIDAndSourceID(ctx, obj.ParentID, *obj.SourceID, obj.Filter)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot count access entries: %w", err))
|
|
}
|
|
return count, nil
|
|
}
|
|
count, err := r.accessReview.Entries(scope).CountForCampaignID(ctx, obj.ParentID, obj.Filter)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot count access entries: %w", err))
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *accessReviewResolver) Organization(ctx context.Context, obj *types.AccessReview) (*types.Organization, error) {
|
|
return obj.Organization, nil
|
|
}
|
|
|
|
// IdentitySource is the resolver for the identitySource field.
|
|
func (r *accessReviewResolver) IdentitySource(ctx context.Context, obj *types.AccessReview) (*types.AccessSource, error) {
|
|
return obj.IdentitySource, nil
|
|
}
|
|
|
|
// AccessSources is the resolver for the accessSources field.
|
|
func (r *accessReviewResolver) AccessSources(ctx context.Context, obj *types.AccessReview, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessSourceOrder) (*types.AccessSourceConnection, error) {
|
|
if err := r.authorize(ctx, obj.Organization.ID, probo.ActionAccessSourceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.Organization.ID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessSourceOrderField]{
|
|
Field: coredata.AccessSourceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessSourceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.Sources(scope).ListForOrganizationID(ctx, obj.Organization.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access sources: %w", err))
|
|
}
|
|
|
|
return types.NewAccessSourceConnection(p, r, obj.Organization.ID), nil
|
|
}
|
|
|
|
// Campaigns is the resolver for the campaigns field.
|
|
func (r *accessReviewResolver) Campaigns(ctx context.Context, obj *types.AccessReview, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessReviewCampaignOrder) (*types.AccessReviewCampaignConnection, error) {
|
|
if err := r.authorize(ctx, obj.Organization.ID, probo.ActionAccessReviewCampaignList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.Organization.ID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessReviewCampaignOrderField]{
|
|
Field: coredata.AccessReviewCampaignOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessReviewCampaignOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.Campaigns(scope).ListForOrganizationID(ctx, obj.Organization.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access review campaigns: %w", err))
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignConnection(p, r, obj.Organization.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessReviewResolver) Permission(ctx context.Context, obj *types.AccessReview, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *accessReviewCampaignResolver) Organization(ctx context.Context, obj *types.AccessReviewCampaign) (*types.Organization, error) {
|
|
return obj.Organization, nil
|
|
}
|
|
|
|
// ScopeSources is the resolver for the scopeSources field.
|
|
func (r *accessReviewCampaignResolver) ScopeSources(ctx context.Context, obj *types.AccessReviewCampaign) ([]*types.AccessReviewCampaignScopeSource, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessSourceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
sources, err := r.accessReview.Sources(scope).ListScopeSourcesForCampaignID(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list scope sources: %w", err))
|
|
}
|
|
|
|
fetches, err := r.accessReview.Campaigns(scope).ListSourceFetches(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list source fetch states: %w", err))
|
|
}
|
|
|
|
fetchBySourceID := make(map[gid.GID]*coredata.AccessReviewCampaignSourceFetch, len(fetches))
|
|
for _, fetch := range fetches {
|
|
fetchBySourceID[fetch.AccessSourceID] = fetch
|
|
}
|
|
|
|
result := make([]*types.AccessReviewCampaignScopeSource, len(sources))
|
|
for i, s := range sources {
|
|
result[i] = types.NewAccessReviewCampaignScopeSource(obj.ID, s, fetchBySourceID[s.ID])
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Entries is the resolver for the entries field.
|
|
func (r *accessReviewCampaignResolver) Entries(ctx context.Context, obj *types.AccessReviewCampaign, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessEntryOrder, accessSourceID *gid.GID, filter *coredata.AccessEntryFilter) (*types.AccessEntryConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessEntryList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessEntryOrderField]{
|
|
Field: coredata.AccessEntryOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessEntryOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var (
|
|
p *page.Page[*coredata.AccessEntry, coredata.AccessEntryOrderField]
|
|
err error
|
|
)
|
|
|
|
if accessSourceID != nil {
|
|
p, err = r.accessReview.Entries(scope).ListForCampaignIDAndSourceID(ctx, obj.ID, *accessSourceID, cursor, filter)
|
|
} else {
|
|
p, err = r.accessReview.Entries(scope).ListForCampaignID(ctx, obj.ID, cursor, filter)
|
|
}
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access entries: %w", err))
|
|
}
|
|
|
|
return types.NewAccessEntryConnection(p, r, obj.ID, accessSourceID, filter), nil
|
|
}
|
|
|
|
// PendingEntryCount is the resolver for the pendingEntryCount field.
|
|
func (r *accessReviewCampaignResolver) PendingEntryCount(ctx context.Context, obj *types.AccessReviewCampaign) (int, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessEntryList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
count, err := r.accessReview.Entries(scope).CountPendingForCampaignID(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot count pending access entries: %w", err))
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Statistics is the resolver for the statistics field.
|
|
func (r *accessReviewCampaignResolver) Statistics(ctx context.Context, obj *types.AccessReviewCampaign) (*types.AccessReviewCampaignStatistics, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessEntryList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
stats, err := r.accessReview.Entries(scope).Statistics(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get campaign statistics: %w", err))
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignStatistics(stats), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessReviewCampaignResolver) Permission(ctx context.Context, obj *types.AccessReviewCampaign, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessReviewCampaignConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessReviewCampaignConnection) (int, error) {
|
|
scope := coredata.NewScopeFromObjectID(obj.ParentID)
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.accessReview.Campaigns(scope).CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot count access review campaigns: %w", err))
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
|
}
|
|
|
|
// Entries is the resolver for the entries field.
|
|
func (r *accessReviewCampaignScopeSourceResolver) Entries(ctx context.Context, obj *types.AccessReviewCampaignScopeSource, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessEntryOrder, filter *coredata.AccessEntryFilter) (*types.AccessEntryConnection, error) {
|
|
if err := r.authorize(ctx, obj.CampaignID, probo.ActionAccessEntryList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.CampaignID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessEntryOrderField]{
|
|
Field: coredata.AccessEntryOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessEntryOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.Entries(scope).ListForCampaignIDAndSourceID(ctx, obj.CampaignID, obj.ID, cursor, filter)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access entries: %w", err))
|
|
}
|
|
|
|
sourceID := obj.ID
|
|
return types.NewAccessEntryConnection(p, r, obj.CampaignID, &sourceID, filter), nil
|
|
}
|
|
|
|
// Statistics is the resolver for the statistics field.
|
|
func (r *accessReviewCampaignScopeSourceResolver) Statistics(ctx context.Context, obj *types.AccessReviewCampaignScopeSource) (*types.AccessReviewCampaignStatistics, error) {
|
|
if err := r.authorize(ctx, obj.CampaignID, probo.ActionAccessEntryList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.CampaignID)
|
|
|
|
stats, err := r.accessReview.Entries(scope).StatisticsForSource(ctx, obj.CampaignID, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get source statistics: %w", err))
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignStatistics(stats), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *accessSourceResolver) Organization(ctx context.Context, obj *types.AccessSource) (*types.Organization, error) {
|
|
return obj.Organization, nil
|
|
}
|
|
|
|
// Connector is the resolver for the connector field.
|
|
func (r *accessSourceResolver) Connector(ctx context.Context, obj *types.AccessSource) (*types.Connector, error) {
|
|
if obj.ConnectorID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
connector, err := prb.Connectors.Get(ctx, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
panic(fmt.Errorf("cannot get connector: %w", err))
|
|
}
|
|
|
|
return types.NewConnector(connector), nil
|
|
}
|
|
|
|
// ProviderOrganizations is the resolver for the providerOrganizations field.
|
|
func (r *accessSourceResolver) ProviderOrganizations(ctx context.Context, obj *types.AccessSource) ([]*types.ProviderOrganization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessSourceGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.ConnectorID == nil {
|
|
return []*types.ProviderOrganization{}, nil
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
httpClient, dbConnector, err := r.accessReview.Sources(scope).ConnectorHTTPClient(ctx, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return []*types.ProviderOrganization{}, nil
|
|
}
|
|
return nil, fmt.Errorf("cannot get connector HTTP client: %w", err)
|
|
}
|
|
|
|
switch dbConnector.Provider {
|
|
case coredata.ConnectorProviderGitHub:
|
|
orgs, err := fetchGitHubOrganizations(ctx, httpClient)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot fetch github organizations: %w", err)
|
|
}
|
|
return orgs, nil
|
|
case coredata.ConnectorProviderSentry:
|
|
orgs, err := fetchSentryOrganizations(ctx, httpClient)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot fetch sentry organizations: %w", err)
|
|
}
|
|
return orgs, nil
|
|
default:
|
|
return []*types.ProviderOrganization{}, nil
|
|
}
|
|
}
|
|
|
|
// NeedsConfiguration is the resolver for the needsConfiguration field.
|
|
func (r *accessSourceResolver) NeedsConfiguration(ctx context.Context, obj *types.AccessSource) (bool, error) {
|
|
if obj.ConnectorID == nil {
|
|
return false, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
dbConnector, err := prb.Connectors.Get(ctx, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return false, nil
|
|
}
|
|
panic(fmt.Errorf("cannot get connector: %w", err))
|
|
}
|
|
|
|
switch dbConnector.Provider {
|
|
case coredata.ConnectorProviderGitHub:
|
|
settings, _ := dbConnector.GitHubSettings()
|
|
return settings.Organization == "", nil
|
|
case coredata.ConnectorProviderSentry:
|
|
settings, _ := dbConnector.SentrySettings()
|
|
return settings.OrganizationSlug == "", nil
|
|
default:
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
// ConnectionStatus is the resolver for the connectionStatus field.
|
|
func (r *accessSourceResolver) ConnectionStatus(ctx context.Context, obj *types.AccessSource) (types.AccessSourceConnectionStatus, error) {
|
|
if obj.ConnectorID == nil {
|
|
return types.AccessSourceConnectionStatusNotApplicable, nil
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
httpClient, dbConnector, err := r.accessReview.Sources(scope).ConnectorHTTPClient(ctx, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return types.AccessSourceConnectionStatusNotApplicable, nil
|
|
}
|
|
return types.AccessSourceConnectionStatusDisconnected, nil
|
|
}
|
|
|
|
if dbConnector.Protocol != coredata.ConnectorProtocolOAuth2 {
|
|
return types.AccessSourceConnectionStatusConnected, nil
|
|
}
|
|
|
|
// Creating an HTTP client may succeed even with an expired token
|
|
// (e.g. no refresh token available). Make a lightweight probe
|
|
// request to verify the token is actually valid.
|
|
probeURL := r.connectorRegistry.GetProbeURL(string(dbConnector.Provider))
|
|
if err := probeConnection(ctx, httpClient, probeURL); err != nil {
|
|
return types.AccessSourceConnectionStatusDisconnected, nil
|
|
}
|
|
|
|
return types.AccessSourceConnectionStatusConnected, nil
|
|
}
|
|
|
|
// SelectedOrganization is the resolver for the selectedOrganization field.
|
|
func (r *accessSourceResolver) SelectedOrganization(ctx context.Context, obj *types.AccessSource) (*string, error) {
|
|
if obj.ConnectorID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
dbConnector, err := prb.Connectors.Get(ctx, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
panic(fmt.Errorf("cannot get connector: %w", err))
|
|
}
|
|
|
|
switch dbConnector.Provider {
|
|
case coredata.ConnectorProviderGitHub:
|
|
settings, _ := dbConnector.GitHubSettings()
|
|
if settings.Organization != "" {
|
|
return &settings.Organization, nil
|
|
}
|
|
case coredata.ConnectorProviderSentry:
|
|
settings, _ := dbConnector.SentrySettings()
|
|
if settings.OrganizationSlug != "" {
|
|
return &settings.OrganizationSlug, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessSourceResolver) Permission(ctx context.Context, obj *types.AccessSource, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessSourceConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessSourceConnection) (int, error) {
|
|
scope := coredata.NewScopeFromObjectID(obj.ParentID)
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.accessReview.Sources(scope).CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot count access sources: %w", err))
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
|
}
|
|
|
|
// StatementOfApplicability is the resolver for the statementOfApplicability field.
|
|
func (r *applicabilityStatementResolver) StatementOfApplicability(ctx context.Context, obj *types.ApplicabilityStatement) (*types.StatementOfApplicability, error) {
|
|
if err := r.authorize(ctx, obj.StatementOfApplicability.ID, probo.ActionStatementOfApplicabilityGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.StatementOfApplicability.ID.TenantID())
|
|
|
|
soa, err := prb.StatementsOfApplicability.Get(ctx, obj.StatementOfApplicability.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get statement of applicability", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewStatementOfApplicability(soa), nil
|
|
}
|
|
|
|
// Control is the resolver for the control field.
|
|
func (r *applicabilityStatementResolver) Control(ctx context.Context, obj *types.ApplicabilityStatement) (*types.Control, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
control, err := loaders.Control.Load(ctx, obj.Control.ID)
|
|
if err != nil {
|
|
if errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get control", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControl(control), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *applicabilityStatementResolver) Permission(ctx context.Context, obj *types.ApplicabilityStatement, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *applicabilityStatementConnectionResolver) TotalCount(ctx context.Context, obj *types.ApplicabilityStatementConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionApplicabilityStatementList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *statementOfApplicabilityResolver:
|
|
count, err := prb.StatementsOfApplicability.CountApplicabilityStatements(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count applicability statements", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver for applicability statement connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *assetResolver) Owner(ctx context.Context, obj *types.Asset) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// Vendors is the resolver for the vendors field.
|
|
func (r *assetResolver) Vendors(ctx context.Context, obj *types.Asset, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
|
Field: coredata.VendorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Vendors.ListForAssetID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list asset vendors", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *assetResolver) Organization(ctx context.Context, obj *types.Asset) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
asset, err := prb.Assets.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
org, err := prb.Organizations.Get(ctx, asset.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(org), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *assetResolver) Permission(ctx context.Context, obj *types.Asset, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *assetConnectionResolver) TotalCount(ctx context.Context, obj *types.AssetConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionAssetList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
assetFilter := coredata.NewAssetFilter(nil)
|
|
if obj.Filter != nil {
|
|
assetFilter = coredata.NewAssetFilter(&obj.Filter.SnapshotID)
|
|
}
|
|
|
|
count, err := prb.Assets.CountForOrganizationID(ctx, obj.ParentID, assetFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count assets", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *auditResolver) Organization(ctx context.Context, obj *types.Audit) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Framework is the resolver for the framework field.
|
|
func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types.Framework, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
framework, err := loaders.Framework.Load(ctx, obj.Framework.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFramework(framework), nil
|
|
}
|
|
|
|
// Report is the resolver for the report field.
|
|
func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionReportGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Report == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
report, err := loaders.Report.Load(ctx, obj.Report.ID)
|
|
if err != nil {
|
|
if errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewReport(report), nil
|
|
}
|
|
|
|
// ReportURL is the resolver for the reportUrl field.
|
|
func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionReportGetReportUrl); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Report == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
url, err := prb.Audits.GenerateReportURL(ctx, obj.ID, 15*time.Minute)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate report URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return url, nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *auditResolver) Controls(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForAuditID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list audit controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// Findings is the resolver for the findings field.
|
|
func (r *auditResolver) Findings(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
|
Field: coredata.FindingOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var (
|
|
kind *coredata.FindingKind
|
|
status *coredata.FindingStatus
|
|
priority *coredata.FindingPriority
|
|
ownerID *gid.GID
|
|
)
|
|
if filter != nil {
|
|
kind = filter.Kind
|
|
status = filter.Status
|
|
priority = filter.Priority
|
|
ownerID = filter.OwnerID
|
|
}
|
|
|
|
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
|
if filter != nil {
|
|
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
|
}
|
|
|
|
p, err := prb.Findings.ListForAuditID(ctx, obj.ID, cursor, findingFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list audit findings", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFindingConnection(p, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *auditResolver) Permission(ctx context.Context, obj *types.Audit, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *auditConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionAuditList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Audits.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *findingResolver:
|
|
count, err := prb.Audits.CountForFindingID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *controlResolver:
|
|
count, err := prb.Audits.CountForControlID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count audits", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
default:
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *auditLogEntryResolver) Organization(ctx context.Context, obj *types.AuditLogEntry) (*types.Organization, error) {
|
|
return obj.Organization, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *auditLogEntryResolver) Permission(ctx context.Context, obj *types.AuditLogEntry, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *auditLogEntryConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditLogEntryConnection) (int, error) {
|
|
filter := coredata.NewAuditLogEntryFilter()
|
|
if obj.Filter != nil {
|
|
filter = obj.Filter
|
|
}
|
|
|
|
count, err := r.iam.OrganizationService.CountAuditLogEntries(ctx, obj.ParentID, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count audit log entries", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *complianceExternalURLResolver) Permission(ctx context.Context, obj *types.ComplianceExternalURL, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Framework is the resolver for the framework field.
|
|
func (r *complianceFrameworkResolver) Framework(ctx context.Context, obj *types.ComplianceFramework) (*types.Framework, error) {
|
|
if err := r.authorize(ctx, obj.FrameworkID, probo.ActionFrameworkGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
framework, err := loaders.Framework.Load(ctx, obj.FrameworkID)
|
|
if err != nil {
|
|
if errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFramework(framework), nil
|
|
}
|
|
|
|
// Oauth2Scopes is the resolver for the oauth2Scopes field.
|
|
func (r *connectorResolver) Oauth2Scopes(ctx context.Context, obj *types.Connector) ([]string, error) {
|
|
scopes := drivers.ProviderOAuth2Scopes(obj.Provider)
|
|
if scopes == nil {
|
|
return []string{}, nil
|
|
}
|
|
return scopes, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *controlResolver) Organization(ctx context.Context, obj *types.Control) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Regulatory is the resolver for the regulatory field.
|
|
func (r *controlResolver) Regulatory(ctx context.Context, obj *types.Control) (bool, error) {
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
hasRegulatory, err := prb.Controls.HasRegulatoryObligation(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot check regulatory obligation", log.Error(err))
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return hasRegulatory, nil
|
|
}
|
|
|
|
// Contractual is the resolver for the contractual field.
|
|
func (r *controlResolver) Contractual(ctx context.Context, obj *types.Control) (bool, error) {
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
hasContractual, err := prb.Controls.HasContractualObligation(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot check contractual obligation", log.Error(err))
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return hasContractual, nil
|
|
}
|
|
|
|
// RiskAssessment is the resolver for the riskAssessment field.
|
|
func (r *controlResolver) RiskAssessment(ctx context.Context, obj *types.Control) (bool, error) {
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
hasRisk, err := prb.Controls.HasRiskAssessment(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot check risk assessment", log.Error(err))
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return hasRisk, nil
|
|
}
|
|
|
|
// Framework is the resolver for the framework field.
|
|
func (r *controlResolver) Framework(ctx context.Context, obj *types.Control) (*types.Framework, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
framework, err := loaders.Framework.Load(ctx, obj.Framework.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFramework(framework), nil
|
|
}
|
|
|
|
// Measures is the resolver for the measures field.
|
|
func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: coredata.MeasureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var measureFilter = coredata.NewMeasureFilter(nil, nil, nil)
|
|
if filter != nil {
|
|
measureFilter = coredata.NewMeasureFilter(filter.Query, filter.State, filter.Category)
|
|
}
|
|
|
|
page, err := prb.Measures.ListForControlID(ctx, obj.ID, cursor, measureFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeasureConnection(page, r, obj.ID, measureFilter), nil
|
|
}
|
|
|
|
// Documents is the resolver for the documents field.
|
|
func (r *controlResolver) Documents(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var documentFilter = coredata.NewDocumentFilter(nil)
|
|
if filter != nil {
|
|
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
|
WithDocumentTypes(filter.DocumentTypes).
|
|
WithClassifications(filter.Classifications)
|
|
}
|
|
|
|
page, err := prb.Documents.ListForControlID(ctx, obj.ID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentConnection(page, r, obj.ID, documentFilter), nil
|
|
}
|
|
|
|
// Audits is the resolver for the audits field.
|
|
func (r *controlResolver) Audits(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
|
Field: coredata.AuditOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Audits.ListForControlID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list control audits", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAuditConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Obligations is the resolver for the obligations field.
|
|
func (r *controlResolver) Obligations(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionObligationList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: coredata.ObligationOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var snapshotID **gid.GID
|
|
if filter != nil {
|
|
snapshotID = &filter.SnapshotID
|
|
}
|
|
obligationFilter := coredata.NewObligationFilter(snapshotID)
|
|
page, err := prb.Obligations.ListForControlID(ctx, obj.ID, cursor, obligationFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list control obligations", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Snapshots is the resolver for the snapshots field.
|
|
func (r *controlResolver) Snapshots(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionSnapshotList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.SnapshotOrderField]{
|
|
Field: coredata.SnapshotOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.SnapshotOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Snapshots.ListForControlID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list control snapshots", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewSnapshotConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *controlResolver) Permission(ctx context.Context, obj *types.Control, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *controlConnectionResolver) TotalCount(ctx context.Context, obj *types.ControlConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionControlList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Controls.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *frameworkResolver:
|
|
count, err := prb.Controls.CountForFrameworkID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *documentResolver:
|
|
count, err := prb.Controls.CountForDocumentID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *measureResolver:
|
|
count, err := prb.Controls.CountForMeasureID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *riskResolver:
|
|
count, err := prb.Controls.CountForRiskID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *statementOfApplicabilityResolver:
|
|
count, err := prb.Controls.CountForStatementOfApplicabilityID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *customDomainResolver) Permission(ctx context.Context, obj *types.CustomDomain, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// ProcessingActivity is the resolver for the processingActivity field.
|
|
func (r *dataProtectionImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.ProcessingActivity, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
processingActivity, err := prb.ProcessingActivities.Get(ctx, dpia.ProcessingActivityID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProcessingActivity(processingActivity), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *dataProtectionImpactAssessmentResolver) Organization(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
organization, err := prb.Organizations.Get(ctx, dpia.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *dataProtectionImpactAssessmentResolver) Permission(ctx context.Context, obj *types.DataProtectionImpactAssessment, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *dataProtectionImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.DataProtectionImpactAssessmentConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDataProtectionImpactAssessmentList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.DataProtectionImpactAssessments.CountForOrganizationID(ctx, obj.ParentID, obj.Filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count organization data protection impact assessments", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *datumResolver) Owner(ctx context.Context, obj *types.Datum) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
return nil, fmt.Errorf("cannot get owner: %w", err)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// Vendors is the resolver for the vendors field.
|
|
func (r *datumResolver) Vendors(ctx context.Context, obj *types.Datum, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
|
Field: coredata.VendorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Data.ListVendors(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list data vendors", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *datumResolver) Organization(ctx context.Context, obj *types.Datum) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
org, err := loaders.Organization.Load(ctx, obj.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(org), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *datumResolver) Permission(ctx context.Context, obj *types.Datum, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *datumConnectionResolver) TotalCount(ctx context.Context, obj *types.DatumConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDatumList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
datumFilter := coredata.NewDatumFilter(nil)
|
|
if obj.Filter != nil {
|
|
datumFilter = coredata.NewDatumFilter(&obj.Filter.SnapshotID)
|
|
}
|
|
|
|
count, err := prb.Data.CountForOrganizationID(ctx, obj.ParentID, datumFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count data", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *documentResolver) Organization(ctx context.Context, obj *types.Document) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Versions is the resolver for the versions field.
|
|
func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy, filter *types.DocumentVersionFilter) (*types.DocumentVersionConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentVersionOrderField]{
|
|
Field: coredata.DocumentVersionOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentVersionOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
versionFilter := coredata.NewDocumentVersionFilter()
|
|
if filter != nil && len(filter.Statuses) > 0 {
|
|
versionFilter = versionFilter.WithStatuses(filter.Statuses...)
|
|
}
|
|
|
|
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list document versions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *documentResolver) Controls(ctx context.Context, obj *types.Document, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForDocumentID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list document controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// DefaultApprovers is the resolver for the defaultApprovers field.
|
|
func (r *documentResolver) DefaultApprovers(ctx context.Context, obj *types.Document) ([]*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
profiles, err := prb.Documents.GetDefaultApprovers(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get default approvers", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
result := make([]*types.Profile, len(profiles))
|
|
for i, p := range profiles {
|
|
result[i] = types.NewProfile(p)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *documentResolver) Permission(ctx context.Context, obj *types.Document, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *documentConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDocumentList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *controlResolver:
|
|
count, err := prb.Documents.CountForControlID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *organizationResolver:
|
|
count, err := prb.Documents.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count documents", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *riskResolver:
|
|
count, err := prb.Documents.CountForRiskID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count risks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *measureResolver:
|
|
count, err := prb.Documents.CountForMeasureID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count documents", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Document is the resolver for the document field.
|
|
func (r *documentVersionResolver) Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
document, err := loaders.Document.Load(ctx, obj.Document.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), nil
|
|
}
|
|
|
|
// Approvers is the resolver for the approvers field.
|
|
func (r *documentVersionResolver) Approvers(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy) (*types.ProfileConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
|
return &types.ProfileConnection{
|
|
Resolver: r,
|
|
ParentID: obj.ID,
|
|
}, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
|
Field: coredata.MembershipProfileOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy.Field = coredata.MembershipProfileOrderField(orderBy.Field)
|
|
pageOrderBy.Direction = page.OrderDirection(orderBy.Direction)
|
|
}
|
|
|
|
c := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := prb.Documents.ListVersionApprovers(ctx, obj.ID, c)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list document version approvers", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfileConnection(p, r, obj.ID, nil), nil
|
|
}
|
|
|
|
// Signatures is the resolver for the signatures field.
|
|
func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder, filter *types.DocumentVersionSignatureFilter) (*types.DocumentVersionSignatureConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionSignatureList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentVersionSignatureOrderField]{
|
|
Field: coredata.DocumentVersionSignatureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentVersionSignatureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
var signatureStates []coredata.DocumentVersionSignatureState
|
|
var activeContract *bool
|
|
if filter != nil {
|
|
if filter.States != nil {
|
|
signatureStates = filter.States
|
|
}
|
|
if filter.ActiveContract != nil {
|
|
activeContract = filter.ActiveContract
|
|
}
|
|
}
|
|
signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract)
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Documents.ListSignatures(ctx, obj.ID, cursor, signatureFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list document version signatures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionSignatureConnection(page, r, obj.ID, signatureFilter), nil
|
|
}
|
|
|
|
// ApprovalQuorums is the resolver for the approvalQuorums field.
|
|
func (r *documentVersionResolver) ApprovalQuorums(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionApprovalQuorumOrder) (*types.DocumentVersionApprovalQuorumConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionApprovalList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentVersionApprovalQuorumOrderField]{
|
|
Field: coredata.DocumentVersionApprovalQuorumOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentVersionApprovalQuorumOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := prb.DocumentApprovals.ListQuorums(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list approval quorums", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionApprovalQuorumConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// Signed is the resolver for the signed field.
|
|
func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.DocumentVersion) (bool, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionGet); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
signed, err := prb.Documents.IsVersionSignedByUserEmail(ctx, obj.ID, identity.EmailAddress)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot check if document version is signed", log.Error(err))
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return signed, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *documentVersionResolver) Permission(ctx context.Context, obj *types.DocumentVersion, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Quorum is the resolver for the quorum field.
|
|
func (r *documentVersionApprovalDecisionResolver) Quorum(ctx context.Context, obj *types.DocumentVersionApprovalDecision) (*types.DocumentVersionApprovalQuorum, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionApprovalList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
quorum, err := prb.DocumentApprovals.GetQuorum(ctx, obj.Quorum.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get approval quorum", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionApprovalQuorum(quorum), nil
|
|
}
|
|
|
|
// DocumentVersion is the resolver for the documentVersion field.
|
|
func (r *documentVersionApprovalDecisionResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionApprovalDecision) (*types.DocumentVersion, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
quorum, err := prb.DocumentApprovals.GetQuorum(ctx, obj.Quorum.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get approval quorum", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
documentVersion, err := prb.Documents.GetVersion(ctx, quorum.VersionID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersion(documentVersion), nil
|
|
}
|
|
|
|
// Approver is the resolver for the approver field.
|
|
func (r *documentVersionApprovalDecisionResolver) Approver(ctx context.Context, obj *types.DocumentVersionApprovalDecision) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profile, err := r.iam.OrganizationService.GetProfile(ctx, obj.Approver.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get approver profile", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(profile), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *documentVersionApprovalDecisionResolver) Permission(ctx context.Context, obj *types.DocumentVersionApprovalDecision, action string) (bool, error) {
|
|
// Approve and reject actions are only allowed for the viewer's own decision.
|
|
if action == probo.ActionDocumentVersionApprove || action == probo.ActionDocumentVersionReject {
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
profile, err := r.iam.OrganizationService.GetProfile(ctx, obj.Approver.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return false, nil
|
|
}
|
|
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if profile.IdentityID != identity.ID {
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *documentVersionApprovalDecisionConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentVersionApprovalDecisionConnection) (int, error) {
|
|
if obj.ParentID.EntityType() != coredata.DocumentVersionApprovalQuorumEntityType {
|
|
return 0, nil
|
|
}
|
|
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDocumentVersionApprovalList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
filter := coredata.NewDocumentVersionApprovalDecisionFilter(nil)
|
|
if obj.Filters != nil {
|
|
filter = obj.Filters
|
|
}
|
|
|
|
count, err := prb.DocumentApprovals.CountDecisions(ctx, obj.ParentID, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count approval decisions", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// DocumentVersion is the resolver for the documentVersion field.
|
|
func (r *documentVersionApprovalQuorumResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionApprovalQuorum) (*types.DocumentVersion, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
documentVersion, err := prb.Documents.GetVersion(ctx, obj.DocumentVersion.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersion(documentVersion), nil
|
|
}
|
|
|
|
// Decisions is the resolver for the decisions field.
|
|
func (r *documentVersionApprovalQuorumResolver) Decisions(ctx context.Context, obj *types.DocumentVersionApprovalQuorum, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionApprovalDecisionOrder, filter *types.DocumentVersionApprovalDecisionFilter) (*types.DocumentVersionApprovalDecisionConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionApprovalList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentVersionApprovalDecisionOrderField]{
|
|
Field: coredata.DocumentVersionApprovalDecisionOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentVersionApprovalDecisionOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
var approvalStates []coredata.DocumentVersionApprovalDecisionState
|
|
if filter != nil && filter.States != nil {
|
|
approvalStates = filter.States
|
|
}
|
|
approvalFilter := coredata.NewDocumentVersionApprovalDecisionFilter(approvalStates)
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := prb.DocumentApprovals.ListDecisions(ctx, obj.ID, cursor, approvalFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list approval decisions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionApprovalDecisionConnection(p, r, obj.ID, approvalFilter), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *documentVersionApprovalQuorumResolver) Permission(ctx context.Context, obj *types.DocumentVersionApprovalQuorum, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *documentVersionApprovalQuorumConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentVersionApprovalQuorumConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDocumentVersionApprovalList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.DocumentApprovals.CountQuorums(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count approval quorums", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *documentVersionConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentVersionConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDocumentVersionList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *documentResolver:
|
|
filter := &coredata.DocumentVersionFilter{}
|
|
if obj.Filters != nil {
|
|
filter = obj.Filters
|
|
}
|
|
count, err := prb.Documents.CountVersionsForDocumentID(ctx, obj.ParentID, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count document versions", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// DocumentVersion is the resolver for the documentVersion field.
|
|
func (r *documentVersionSignatureResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionSignature) (*types.DocumentVersion, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentVersionGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
documentVersion, err := prb.Documents.GetVersion(ctx, obj.DocumentVersion.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersion(documentVersion), nil
|
|
}
|
|
|
|
// SignedBy is the resolver for the signedBy field.
|
|
func (r *documentVersionSignatureResolver) SignedBy(ctx context.Context, obj *types.DocumentVersionSignature) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
signatory, err := loaders.Profile.Load(ctx, obj.SignedBy.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get people", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(signatory), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *documentVersionSignatureResolver) Permission(ctx context.Context, obj *types.DocumentVersionSignature, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *documentVersionSignatureConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentVersionSignatureConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionDocumentVersionSignatureList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *documentVersionResolver:
|
|
filter := &coredata.DocumentVersionSignatureFilter{}
|
|
if obj.Filters != nil {
|
|
filter = obj.Filters
|
|
}
|
|
count, err := prb.Documents.CountSignaturesForVersionID(ctx, obj.ParentID, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count signatures", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// CertificateFileURL is the resolver for the certificateFileUrl field.
|
|
func (r *electronicSignatureResolver) CertificateFileURL(ctx context.Context, obj *types.ElectronicSignature) (*string, error) {
|
|
signature, err := r.esign.GetSignatureByID(ctx, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot load signature: %w", err)
|
|
}
|
|
|
|
if signature.CertificateFileID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
url, err := r.esign.GenerateCertificateFileURL(ctx, *signature.CertificateFileID, 1*time.Hour)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot generate certificate file URL: %w", err)
|
|
}
|
|
|
|
return &url, nil
|
|
}
|
|
|
|
// Events is the resolver for the events field.
|
|
func (r *electronicSignatureResolver) Events(ctx context.Context, obj *types.ElectronicSignature) ([]*types.ElectronicSignatureEvent, error) {
|
|
events, err := r.esign.GetEventsBySignatureID(ctx, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot load signature events: %w", err)
|
|
}
|
|
|
|
result := make([]*types.ElectronicSignatureEvent, len(events))
|
|
for i := range events {
|
|
result[i] = types.NewElectronicSignatureEvent(events[i])
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Signed is the resolver for the signed field.
|
|
func (r *employeeDocumentResolver) Signed(ctx context.Context, obj *types.EmployeeDocument) (*bool, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
signed, err := prb.Documents.IsSigned(ctx, obj.ID, identity.EmailAddress)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot check if document is signed", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &signed, nil
|
|
}
|
|
|
|
// ApprovalState is the resolver for the approvalState field.
|
|
func (r *employeeDocumentResolver) ApprovalState(ctx context.Context, obj *types.EmployeeDocument) (*coredata.DocumentVersionApprovalDecisionState, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
state, err := prb.Documents.GetViewerApprovalState(ctx, obj.ID, identity.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot get viewer approval state", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &state, nil
|
|
}
|
|
|
|
// Versions is the resolver for the versions field.
|
|
func (r *employeeDocumentResolver) Versions(ctx context.Context, obj *types.EmployeeDocument, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy) (*types.EmployeeDocumentVersionConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentVersionOrderField]{
|
|
Field: coredata.DocumentVersionOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentVersionOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
var filterMode coredata.EmployeeFilterMode
|
|
switch obj.FilterMode {
|
|
case types.EmployeeDocumentFilterModeSignature:
|
|
filterMode = coredata.EmployeeFilterModeSignature
|
|
case types.EmployeeDocumentFilterModeApproval:
|
|
filterMode = coredata.EmployeeFilterModeApproval
|
|
default:
|
|
r.logger.ErrorCtx(ctx, "unsupported employee document filter mode", log.String("filter_mode", string(obj.FilterMode)))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
versionFilter := coredata.NewDocumentVersionFilter().
|
|
WithEmployeeIdentityID(&identity.ID, filterMode)
|
|
|
|
versionsPage, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list employee document versions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
employeeVersions := make([]*types.EmployeeDocumentVersion, len(versionsPage.Data))
|
|
for i, v := range versionsPage.Data {
|
|
employeeVersions[i] = &types.EmployeeDocumentVersion{
|
|
ID: v.ID,
|
|
DocumentID: obj.ID,
|
|
OrganizationID: v.OrganizationID,
|
|
Major: v.Major,
|
|
Minor: v.Minor,
|
|
Status: v.Status,
|
|
Classification: v.Classification,
|
|
DocumentType: v.DocumentType,
|
|
PublishedAt: v.PublishedAt,
|
|
CreatedAt: v.CreatedAt,
|
|
UpdatedAt: v.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
p := page.NewPage(employeeVersions, versionsPage.Cursor)
|
|
|
|
return types.NewEmployeeDocumentVersionConnection(p), nil
|
|
}
|
|
|
|
// Signed is the resolver for the signed field.
|
|
func (r *employeeDocumentVersionResolver) Signed(ctx context.Context, obj *types.EmployeeDocumentVersion) (bool, error) {
|
|
if err := r.authorize(ctx, obj.DocumentID, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
signed, err := prb.Documents.IsVersionSignedByUserEmail(ctx, obj.ID, identity.EmailAddress)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot check if version is signed", log.Error(err))
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return signed, nil
|
|
}
|
|
|
|
// ApprovalDecision is the resolver for the approvalDecision field.
|
|
func (r *employeeDocumentVersionResolver) ApprovalDecision(ctx context.Context, obj *types.EmployeeDocumentVersion) (*types.DocumentVersionApprovalDecision, error) {
|
|
if err := r.authorize(ctx, obj.DocumentID, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
decision, err := prb.DocumentApprovals.GetViewerDecision(ctx, obj.ID, identity.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get viewer approval decision", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentVersionApprovalDecision(decision), nil
|
|
}
|
|
|
|
// File is the resolver for the file field.
|
|
func (r *evidenceResolver) File(ctx context.Context, obj *types.Evidence) (*types.File, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.File == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
file, err := loaders.File.Load(ctx, obj.File.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load evidence file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFile(file), nil
|
|
}
|
|
|
|
// Task is the resolver for the task field.
|
|
func (r *evidenceResolver) Task(ctx context.Context, obj *types.Evidence) (*types.Task, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTaskGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Task == nil {
|
|
r.logger.ErrorCtx(ctx, "evidence is not associated with a task")
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
task, err := loaders.Task.Load(ctx, obj.Task.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load task", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTask(task), nil
|
|
}
|
|
|
|
// Measure is the resolver for the measure field.
|
|
func (r *evidenceResolver) Measure(ctx context.Context, obj *types.Evidence) (*types.Measure, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
measure, err := loaders.Measure.Load(ctx, obj.Measure.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeasure(measure), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *evidenceResolver) Permission(ctx context.Context, obj *types.Evidence, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *evidenceConnectionResolver) TotalCount(ctx context.Context, obj *types.EvidenceConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionEvidenceList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *measureResolver:
|
|
count, err := prb.Evidences.CountForMeasureID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count measure evidence", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *taskResolver:
|
|
count, err := prb.Evidences.CountForTaskID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count task evidence", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// DownloadURL is the resolver for the downloadUrl field.
|
|
func (r *fileResolver) DownloadURL(ctx context.Context, obj *types.File) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFileDownloadUrl); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
downloadUrl, err := prb.Files.GenerateFileTempURL(ctx, obj.ID, 60*time.Second)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate download URL", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return downloadUrl, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *findingResolver) Organization(ctx context.Context, obj *types.Finding) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get finding organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Audits is the resolver for the audits field.
|
|
func (r *findingResolver) Audits(ctx context.Context, obj *types.Finding, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
|
Field: coredata.AuditOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := prb.Audits.ListForFindingID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list finding audits", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAuditConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *findingResolver) Owner(ctx context.Context, obj *types.Finding) (*types.Profile, error) {
|
|
if obj.Owner == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get finding owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// Risk is the resolver for the risk field.
|
|
func (r *findingResolver) Risk(ctx context.Context, obj *types.Finding) (*types.Risk, error) {
|
|
if obj.Risk == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionRiskGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
risk, err := loaders.Risk.Load(ctx, obj.Risk.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get finding risk", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRisk(risk), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *findingResolver) Permission(ctx context.Context, obj *types.Finding, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *findingConnectionResolver) TotalCount(ctx context.Context, obj *types.FindingConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionFindingList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
var (
|
|
kind *coredata.FindingKind
|
|
status *coredata.FindingStatus
|
|
priority *coredata.FindingPriority
|
|
ownerID *gid.GID
|
|
)
|
|
if obj.Filter != nil {
|
|
kind = obj.Filter.Kind
|
|
status = obj.Filter.Status
|
|
priority = obj.Filter.Priority
|
|
ownerID = obj.Filter.OwnerID
|
|
}
|
|
|
|
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
|
if obj.Filter != nil {
|
|
findingFilter = coredata.NewFindingFilter(&obj.Filter.SnapshotID, kind, status, priority, ownerID)
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Findings.CountForOrganizationID(ctx, obj.ParentID, findingFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *auditResolver:
|
|
count, err := prb.Findings.CountForAuditID(ctx, obj.ParentID, findingFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count findings", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver", log.Any("resolver", obj.Resolver))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framework) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForFrameworkID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// LightLogoURL is the resolver for the lightLogoURL field.
|
|
func (r *frameworkResolver) LightLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
return prb.Frameworks.GenerateLightLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
}
|
|
|
|
// DarkLogoURL is the resolver for the darkLogoURL field.
|
|
func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framework) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
return prb.Frameworks.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *frameworkResolver) Permission(ctx context.Context, obj *types.Framework, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *frameworkConnectionResolver) TotalCount(ctx context.Context, obj *types.FrameworkConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionFrameworkList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.Frameworks.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count frameworks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Subscribers is the resolver for the subscribers field on MailingList.
|
|
func (r *mailingListResolver) Subscribers(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListSubscriberConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMailingListSubscriberList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MailingListSubscriberOrderField]{
|
|
Field: coredata.MailingListSubscriberOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := r.mailman.ListSubscribers(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list mailing list subscribers", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMailingListSubscriberConnection(result, r, obj.ID), nil
|
|
}
|
|
|
|
// Updates is the resolver for the updates field on MailingList.
|
|
func (r *mailingListResolver) Updates(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMailingListUpdateList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{
|
|
Field: coredata.MailingListUpdateOrderFieldUpdatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := r.mailman.ListMailingListUpdates(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list mailing list updates", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMailingListUpdateConnection(result, r, obj.ID), nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *mailingListSubscriberConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListSubscriberConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionMailingListSubscriberList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *mailingListResolver:
|
|
count, err := r.mailman.CountSubscribers(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count mailing list subscribers", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver for mailing list subscriber connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field on MailingListUpdateConnection.
|
|
func (r *mailingListUpdateConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListUpdateConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionMailingListUpdateList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
count, err := r.mailman.CountMailingListUpdates(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count mailing list updates", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Evidences is the resolver for the evidences field.
|
|
func (r *measureResolver) Evidences(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionEvidenceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: coredata.EvidenceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Evidences.ListForMeasureID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure evidences", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewEvidenceConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Tasks is the resolver for the tasks field.
|
|
func (r *measureResolver) Tasks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTaskList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TaskOrderField]{
|
|
Field: coredata.TaskOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TaskOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Tasks.ListForMeasureID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure tasks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTaskConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Risks is the resolver for the risks field.
|
|
func (r *measureResolver) Risks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionRiskList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.RiskOrderField]{
|
|
Field: coredata.RiskOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.RiskOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var riskFilter = coredata.NewRiskFilter(nil, nil)
|
|
if filter != nil {
|
|
riskFilter = coredata.NewRiskFilter(filter.Query, &filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Risks.ListForMeasureID(ctx, obj.ID, cursor, riskFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure risks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRiskConnection(page, r, obj.ID, riskFilter), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *measureResolver) Controls(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForMeasureID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// Documents is the resolver for the documents field.
|
|
func (r *measureResolver) Documents(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var documentFilter = coredata.NewDocumentFilter(nil)
|
|
if filter != nil {
|
|
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
|
WithDocumentTypes(filter.DocumentTypes).
|
|
WithClassifications(filter.Classifications)
|
|
}
|
|
|
|
pg, err := prb.Documents.ListForMeasureID(ctx, obj.ID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentConnection(pg, r, obj.ID, documentFilter), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *measureResolver) Permission(ctx context.Context, obj *types.Measure, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *measureConnectionResolver) TotalCount(ctx context.Context, obj *types.MeasureConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionMeasureList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Measures.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *controlResolver:
|
|
count, err := prb.Measures.CountForControlID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *riskResolver:
|
|
count, err := prb.Measures.CountForRiskID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count measures", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Attendees is the resolver for the attendees field.
|
|
func (r *meetingResolver) Attendees(ctx context.Context, obj *types.Meeting) ([]*types.Profile, error) {
|
|
// TODO bug must be paginated
|
|
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
attendees, err := prb.Meetings.GetAttendees(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load meeting attendees", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if len(attendees) == 0 {
|
|
return []*types.Profile{}, nil
|
|
}
|
|
|
|
people := make([]*types.Profile, len(attendees))
|
|
for i, attendee := range attendees {
|
|
people[i] = types.NewProfile(attendee)
|
|
}
|
|
|
|
return people, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *meetingResolver) Organization(ctx context.Context, obj *types.Meeting) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *meetingResolver) Permission(ctx context.Context, obj *types.Meeting, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *meetingConnectionResolver) TotalCount(ctx context.Context, obj *types.MeetingConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionMeetingList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Meetings.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count meetings", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// UpdateOrganizationContext is the resolver for the updateOrganizationContext field.
|
|
func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input types.UpdateOrganizationContextInput) (*types.UpdateOrganizationContextPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.UpdateOrganizationContextRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Product: gqlutils.UnwrapOmittable(input.Product),
|
|
Architecture: gqlutils.UnwrapOmittable(input.Architecture),
|
|
Team: gqlutils.UnwrapOmittable(input.Team),
|
|
Processes: gqlutils.UnwrapOmittable(input.Processes),
|
|
Customers: gqlutils.UnwrapOmittable(input.Customers),
|
|
}
|
|
|
|
organizationContext, err := prb.Organizations.UpdateContext(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update organization context", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateOrganizationContextPayload{
|
|
Context: types.NewOrganizationContext(organizationContext),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTrustCenter is the resolver for the updateTrustCenter field.
|
|
func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionTrustCenterUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
trustCenter, file, err := prb.TrustCenters.Update(
|
|
ctx,
|
|
&probo.UpdateTrustCenterRequest{
|
|
ID: input.TrustCenterID,
|
|
Active: input.Active,
|
|
SearchEngineIndexing: input.SearchEngineIndexing,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update trust center", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTrustCenterPayload{
|
|
TrustCenter: types.NewTrustCenter(trustCenter, file),
|
|
}, nil
|
|
}
|
|
|
|
// UploadTrustCenterNda is the resolver for the uploadTrustCenterNDA field.
|
|
func (r *mutationResolver) UploadTrustCenterNda(ctx context.Context, input types.UploadTrustCenterNDAInput) (*types.UploadTrustCenterNDAPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionTrustCenterNonDisclosureAgreementUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
trustCenter, file, err := prb.TrustCenters.UploadNDA(
|
|
ctx,
|
|
&probo.UploadTrustCenterNDARequest{
|
|
TrustCenterID: input.TrustCenterID,
|
|
File: input.File.File,
|
|
FileName: input.FileName,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload trust center NDA", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadTrustCenterNDAPayload{
|
|
TrustCenter: types.NewTrustCenter(trustCenter, file),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTrustCenterNda is the resolver for the deleteTrustCenterNDA field.
|
|
func (r *mutationResolver) DeleteTrustCenterNda(ctx context.Context, input types.DeleteTrustCenterNDAInput) (*types.DeleteTrustCenterNDAPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionTrustCenterNonDisclosureAgreementDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
trustCenter, file, err := prb.TrustCenters.DeleteNDA(ctx, input.TrustCenterID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete trust center NDA", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTrustCenterNDAPayload{
|
|
TrustCenter: types.NewTrustCenter(trustCenter, file),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTrustCenterBrand is the resolver for the updateTrustCenterBrand field.
|
|
func (r *mutationResolver) UpdateTrustCenterBrand(ctx context.Context, input types.UpdateTrustCenterBrandInput) (*types.UpdateTrustCenterBrandPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionTrustCenterUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
req := &probo.UpdateTrustCenterBrandRequest{
|
|
TrustCenterID: input.TrustCenterID,
|
|
}
|
|
|
|
if input.LogoFile.IsSet() {
|
|
logoFile := input.LogoFile.Value()
|
|
if logoFile == nil {
|
|
var nilFile *probo.FileUpload
|
|
req.LogoFile = &nilFile
|
|
} else {
|
|
fileUpload := &probo.FileUpload{
|
|
Content: logoFile.File,
|
|
Filename: logoFile.Filename,
|
|
Size: logoFile.Size,
|
|
ContentType: logoFile.ContentType,
|
|
}
|
|
req.LogoFile = &fileUpload
|
|
}
|
|
}
|
|
|
|
if input.DarkLogoFile.IsSet() {
|
|
darkLogoFile := input.DarkLogoFile.Value()
|
|
if darkLogoFile == nil {
|
|
var nilFile *probo.FileUpload
|
|
req.DarkLogoFile = &nilFile
|
|
} else {
|
|
fileUpload := &probo.FileUpload{
|
|
Content: darkLogoFile.File,
|
|
Filename: darkLogoFile.Filename,
|
|
Size: darkLogoFile.Size,
|
|
ContentType: darkLogoFile.ContentType,
|
|
}
|
|
req.DarkLogoFile = &fileUpload
|
|
}
|
|
}
|
|
|
|
trustCenter, file, err := prb.TrustCenters.UpdateTrustCenterBrand(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update trust center brand", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTrustCenterBrandPayload{
|
|
TrustCenter: types.NewTrustCenter(trustCenter, file),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTrustCenterAccess is the resolver for the updateTrustCenterAccess field.
|
|
func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input types.UpdateTrustCenterAccessInput) (*types.UpdateTrustCenterAccessPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterAccessUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
var documentAccesses []probo.UpdateTrustCenterDocumentAccessRequest
|
|
var reportAccesses []probo.UpdateTrustCenterDocumentAccessRequest
|
|
var fileAccesses []probo.UpdateTrustCenterDocumentAccessRequest
|
|
for _, documentAccess := range input.Documents {
|
|
documentAccesses = append(documentAccesses, probo.UpdateTrustCenterDocumentAccessRequest{
|
|
ID: documentAccess.ID,
|
|
Status: documentAccess.Status,
|
|
})
|
|
}
|
|
for _, reportAccess := range input.Reports {
|
|
reportAccesses = append(reportAccesses, probo.UpdateTrustCenterDocumentAccessRequest{
|
|
ID: reportAccess.ID,
|
|
Status: reportAccess.Status,
|
|
})
|
|
}
|
|
for _, fileAccess := range input.TrustCenterFiles {
|
|
fileAccesses = append(fileAccesses, probo.UpdateTrustCenterDocumentAccessRequest{
|
|
ID: fileAccess.ID,
|
|
Status: fileAccess.Status,
|
|
})
|
|
}
|
|
access, err := prb.TrustCenterAccesses.Update(
|
|
ctx,
|
|
&probo.UpdateTrustCenterAccessRequest{
|
|
ID: input.ID,
|
|
DocumentAccesses: documentAccesses,
|
|
ReportAccesses: reportAccesses,
|
|
TrustCenterFileAccesses: fileAccesses,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update trust center access", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTrustCenterAccessPayload{
|
|
TrustCenterAccess: types.NewTrustCenterAccess(access),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTrustCenterAccess is the resolver for the deleteTrustCenterAccess field.
|
|
func (r *mutationResolver) DeleteTrustCenterAccess(ctx context.Context, input types.DeleteTrustCenterAccessInput) (*types.DeleteTrustCenterAccessPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterAccessDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
err := prb.TrustCenterAccesses.Delete(ctx, input.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete trust center access", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTrustCenterAccessPayload{
|
|
DeletedTrustCenterAccessID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateMailingListUpdate is the resolver for the createMailingListUpdate field.
|
|
func (r *mutationResolver) CreateMailingListUpdate(ctx context.Context, input types.CreateMailingListUpdateInput) (*types.CreateMailingListUpdatePayload, error) {
|
|
if err := r.authorize(ctx, input.MailingListID, probo.ActionMailingListUpdateCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mlu, err := r.mailman.CreateMailingListUpdate(
|
|
ctx,
|
|
&mailman.CreateMailingListUpdateRequest{
|
|
MailingListID: input.MailingListID,
|
|
Title: input.Title,
|
|
Body: input.Body,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create mailing list update", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateMailingListUpdatePayload{
|
|
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMailingListUpdate is the resolver for the updateMailingListUpdate field.
|
|
func (r *mutationResolver) UpdateMailingListUpdate(ctx context.Context, input types.UpdateMailingListUpdateInput) (*types.UpdateMailingListUpdatePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mlu, err := r.mailman.UpdateMailingListUpdate(
|
|
ctx,
|
|
&mailman.UpdateMailingListUpdateRequest{
|
|
ID: input.ID,
|
|
Title: input.Title,
|
|
Body: input.Body,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
if errors.Is(err, mailman.ErrMailingListUpdateAlreadySent) {
|
|
return nil, gqlutils.Conflictf(ctx, "mailing list update can only be edited when in draft")
|
|
}
|
|
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
|
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update mailing list update", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateMailingListUpdatePayload{
|
|
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
|
}, nil
|
|
}
|
|
|
|
// SendMailingListUpdate is the resolver for the sendMailingListUpdate field.
|
|
func (r *mutationResolver) SendMailingListUpdate(ctx context.Context, input types.SendMailingListUpdateInput) (*types.SendMailingListUpdatePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mlu, err := r.mailman.SendMailingListUpdate(ctx, input.ID)
|
|
if err != nil {
|
|
if errors.Is(err, mailman.ErrMailingListUpdateAlreadySent) {
|
|
return nil, gqlutils.Conflictf(ctx, "mailing list update has already been queued for sending")
|
|
}
|
|
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
|
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot queue mailing list update for sending", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.SendMailingListUpdatePayload{
|
|
MailingListUpdate: types.NewMailingListUpdate(mlu),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMailingListUpdate is the resolver for the deleteMailingListUpdate field.
|
|
func (r *mutationResolver) DeleteMailingListUpdate(ctx context.Context, input types.DeleteMailingListUpdateInput) (*types.DeleteMailingListUpdatePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdateDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.mailman.DeleteMailingListUpdate(ctx, input.ID); err != nil {
|
|
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) {
|
|
return nil, gqlutils.NotFoundf(ctx, "mailing list update not found")
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot delete mailing list update", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteMailingListUpdatePayload{
|
|
DeletedMailingListUpdateID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMailingList is the resolver for the updateMailingList field.
|
|
func (r *mutationResolver) UpdateMailingList(ctx context.Context, input types.UpdateMailingListInput) (*types.UpdateMailingListPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMailingListUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ml, err := r.mailman.UpdateMailingList(ctx, input.ID, input.ReplyTo)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot update mailing list", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateMailingListPayload{
|
|
MailingList: types.NewMailingList(ml),
|
|
}, nil
|
|
}
|
|
|
|
// CreateMailingListSubscriber is the resolver for the createMailingListSubscriber field.
|
|
func (r *mutationResolver) CreateMailingListSubscriber(ctx context.Context, input types.CreateMailingListSubscriberInput) (*types.CreateMailingListSubscriberPayload, error) {
|
|
if err := r.authorize(ctx, input.MailingListID, probo.ActionMailingListSubscriberCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
subscriber, err := r.mailman.CreateSubscriber(
|
|
ctx,
|
|
&mailman.CreateSubscriberRequest{
|
|
MailingListID: input.MailingListID,
|
|
Email: input.Email,
|
|
FullName: input.FullName,
|
|
Confirmed: input.Confirmed != nil && *input.Confirmed,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
if errors.Is(err, mailman.ErrSubscriberAlreadyExist) {
|
|
return nil, gqlutils.Conflictf(ctx, "subscriber already exists in this mailing list")
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create mailing list subscriber", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateMailingListSubscriberPayload{
|
|
MailingListSubscriberEdge: types.NewMailingListSubscriberEdge(subscriber, coredata.MailingListSubscriberOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMailingListSubscriber is the resolver for the deleteMailingListSubscriber field.
|
|
func (r *mutationResolver) DeleteMailingListSubscriber(ctx context.Context, input types.DeleteMailingListSubscriberInput) (*types.DeleteMailingListSubscriberPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMailingListSubscriberDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.mailman.DeleteSubscriber(ctx, input.ID); err != nil {
|
|
if errors.Is(err, mailman.ErrSubscriberNotFound) {
|
|
return nil, gqlutils.NotFoundf(ctx, "mailing list subscriber not found")
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot delete mailing list subscriber", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteMailingListSubscriberPayload{
|
|
DeletedMailingListSubscriberID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateTrustCenterReference is the resolver for the createTrustCenterReference field.
|
|
func (r *mutationResolver) CreateTrustCenterReference(ctx context.Context, input types.CreateTrustCenterReferenceInput) (*types.CreateTrustCenterReferencePayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionTrustCenterReferenceCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
reference, err := prb.TrustCenterReferences.Create(
|
|
ctx,
|
|
&probo.CreateTrustCenterReferenceRequest{
|
|
TrustCenterID: input.TrustCenterID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
WebsiteURL: input.WebsiteURL,
|
|
LogoFile: probo.File{
|
|
Content: input.LogoFile.File,
|
|
Filename: input.LogoFile.Filename,
|
|
Size: input.LogoFile.Size,
|
|
ContentType: input.LogoFile.ContentType,
|
|
},
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create trust center reference", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateTrustCenterReferencePayload{
|
|
TrustCenterReferenceEdge: types.NewTrustCenterReferenceEdge(reference, coredata.TrustCenterReferenceOrderFieldRank),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTrustCenterReference is the resolver for the updateTrustCenterReference field.
|
|
func (r *mutationResolver) UpdateTrustCenterReference(ctx context.Context, input types.UpdateTrustCenterReferenceInput) (*types.UpdateTrustCenterReferencePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterReferenceUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := &probo.UpdateTrustCenterReferenceRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
WebsiteURL: input.WebsiteURL,
|
|
Rank: input.Rank,
|
|
}
|
|
|
|
if input.LogoFile != nil {
|
|
req.LogoFile = &probo.File{
|
|
Content: input.LogoFile.File,
|
|
Filename: input.LogoFile.Filename,
|
|
Size: input.LogoFile.Size,
|
|
ContentType: input.LogoFile.ContentType,
|
|
}
|
|
}
|
|
|
|
reference, err := prb.TrustCenterReferences.Update(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update trust center reference", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTrustCenterReferencePayload{
|
|
TrustCenterReference: types.NewTrustCenterReference(reference),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTrustCenterReference is the resolver for the deleteTrustCenterReference field.
|
|
func (r *mutationResolver) DeleteTrustCenterReference(ctx context.Context, input types.DeleteTrustCenterReferenceInput) (*types.DeleteTrustCenterReferencePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterReferenceDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
err := prb.TrustCenterReferences.Delete(ctx, input.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete trust center reference", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTrustCenterReferencePayload{
|
|
DeletedTrustCenterReferenceID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateComplianceFramework is the resolver for the createComplianceFramework field.
|
|
func (r *mutationResolver) CreateComplianceFramework(ctx context.Context, input types.CreateComplianceFrameworkInput) (*types.CreateComplianceFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionComplianceFrameworkCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
cf, err := prb.ComplianceFrameworks.Create(
|
|
ctx,
|
|
&probo.CreateComplianceFrameworkRequest{
|
|
TrustCenterID: input.TrustCenterID,
|
|
FrameworkID: input.FrameworkID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create compliance framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateComplianceFrameworkPayload{
|
|
ComplianceFrameworkEdge: types.NewComplianceFrameworkEdge(cf, coredata.ComplianceFrameworkOrderFieldRank),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateComplianceFramework is the resolver for the updateComplianceFramework field.
|
|
func (r *mutationResolver) UpdateComplianceFramework(ctx context.Context, input types.UpdateComplianceFrameworkInput) (*types.UpdateComplianceFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionComplianceFrameworkUpdateRank); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
cf, err := prb.ComplianceFrameworks.Update(ctx, &probo.UpdateComplianceFrameworkRequest{
|
|
ID: input.ID,
|
|
Rank: input.Rank,
|
|
})
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update compliance framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateComplianceFrameworkPayload{
|
|
ComplianceFramework: types.NewComplianceFramework(cf),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteComplianceFramework is the resolver for the deleteComplianceFramework field.
|
|
func (r *mutationResolver) DeleteComplianceFramework(ctx context.Context, input types.DeleteComplianceFrameworkInput) (*types.DeleteComplianceFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionComplianceFrameworkDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
err := prb.ComplianceFrameworks.Delete(
|
|
ctx,
|
|
&probo.DeleteComplianceFrameworkRequest{
|
|
ID: input.ID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot delete compliance framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteComplianceFrameworkPayload{
|
|
DeletedComplianceFrameworkID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateComplianceExternalURL is the resolver for the createComplianceExternalURL field.
|
|
func (r *mutationResolver) CreateComplianceExternalURL(ctx context.Context, input types.CreateComplianceExternalURLInput) (*types.CreateComplianceExternalURLPayload, error) {
|
|
if err := r.authorize(ctx, input.TrustCenterID, probo.ActionComplianceExternalURLCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())
|
|
|
|
item, err := prb.ComplianceExternalURLs.Create(
|
|
ctx,
|
|
&probo.CreateComplianceExternalURLRequest{
|
|
TrustCenterID: input.TrustCenterID,
|
|
Name: input.Name,
|
|
URL: input.URL,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create compliance external URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateComplianceExternalURLPayload{
|
|
ComplianceExternalURLEdge: types.NewComplianceExternalURLEdge(item, coredata.ComplianceExternalURLOrderFieldRank),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateComplianceExternalURL is the resolver for the updateComplianceExternalURL field.
|
|
func (r *mutationResolver) UpdateComplianceExternalURL(ctx context.Context, input types.UpdateComplianceExternalURLInput) (*types.UpdateComplianceExternalURLPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionComplianceExternalURLUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
item, err := prb.ComplianceExternalURLs.Update(ctx, &probo.UpdateComplianceExternalURLRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
URL: input.URL,
|
|
Rank: input.Rank,
|
|
})
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update compliance external URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateComplianceExternalURLPayload{
|
|
ComplianceExternalURL: types.NewComplianceExternalURL(item),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteComplianceExternalURL is the resolver for the deleteComplianceExternalURL field.
|
|
func (r *mutationResolver) DeleteComplianceExternalURL(ctx context.Context, input types.DeleteComplianceExternalURLInput) (*types.DeleteComplianceExternalURLPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionComplianceExternalURLDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
if err := prb.ComplianceExternalURLs.Delete(ctx, &probo.DeleteComplianceExternalURLRequest{ID: input.ID}); err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot delete compliance external URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteComplianceExternalURLPayload{
|
|
DeletedComplianceExternalURLID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateTrustCenterFile is the resolver for the createTrustCenterFile field.
|
|
func (r *mutationResolver) CreateTrustCenterFile(ctx context.Context, input types.CreateTrustCenterFileInput) (*types.CreateTrustCenterFilePayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionTrustCenterFileCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
file, err := prb.TrustCenterFiles.Create(
|
|
ctx,
|
|
&probo.CreateTrustCenterFileRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Category: input.Category,
|
|
File: probo.File{
|
|
Content: input.File.File,
|
|
Filename: input.File.Filename,
|
|
Size: input.File.Size,
|
|
ContentType: input.File.ContentType,
|
|
},
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateTrustCenterFilePayload{
|
|
TrustCenterFileEdge: types.NewTrustCenterFileEdge(file, coredata.TrustCenterFileOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTrustCenterFile is the resolver for the updateTrustCenterFile field.
|
|
func (r *mutationResolver) UpdateTrustCenterFile(ctx context.Context, input types.UpdateTrustCenterFileInput) (*types.UpdateTrustCenterFilePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterFileUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
file, err := prb.TrustCenterFiles.Update(
|
|
ctx,
|
|
&probo.UpdateTrustCenterFileRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Category: input.Category,
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTrustCenterFilePayload{
|
|
TrustCenterFile: types.NewTrustCenterFile(file),
|
|
}, nil
|
|
}
|
|
|
|
// GetTrustCenterFile is the resolver for the getTrustCenterFile field.
|
|
func (r *mutationResolver) GetTrustCenterFile(ctx context.Context, input types.GetTrustCenterFileInput) (*types.GetTrustCenterFilePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterFileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
file, err := prb.TrustCenterFiles.Get(ctx, input.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.GetTrustCenterFilePayload{
|
|
TrustCenterFile: types.NewTrustCenterFile(file),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTrustCenterFile is the resolver for the deleteTrustCenterFile field.
|
|
func (r *mutationResolver) DeleteTrustCenterFile(ctx context.Context, input types.DeleteTrustCenterFileInput) (*types.DeleteTrustCenterFilePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTrustCenterFileDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
err := prb.TrustCenterFiles.Delete(ctx, input.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTrustCenterFilePayload{
|
|
DeletedTrustCenterFileID: input.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendor is the resolver for the createVendor field.
|
|
func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionVendorCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Create(
|
|
ctx,
|
|
probo.CreateVendorRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
StatusPageURL: input.StatusPageURL,
|
|
TermsOfServiceURL: input.TermsOfServiceURL,
|
|
PrivacyPolicyURL: input.PrivacyPolicyURL,
|
|
ServiceLevelAgreementURL: input.ServiceLevelAgreementURL,
|
|
LegalName: input.LegalName,
|
|
HeadquarterAddress: input.HeadquarterAddress,
|
|
WebsiteURL: input.WebsiteURL,
|
|
Category: input.Category,
|
|
DataProcessingAgreementURL: input.DataProcessingAgreementURL,
|
|
BusinessAssociateAgreementURL: input.BusinessAssociateAgreementURL,
|
|
SubprocessorsListURL: input.SubprocessorsListURL,
|
|
Certifications: input.Certifications,
|
|
SecurityPageURL: input.SecurityPageURL,
|
|
TrustPageURL: input.TrustPageURL,
|
|
BusinessOwnerID: input.BusinessOwnerID,
|
|
SecurityOwnerID: input.SecurityOwnerID,
|
|
Countries: input.Countries,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
return &types.CreateVendorPayload{
|
|
VendorEdge: types.NewVendorEdge(vendor, coredata.VendorOrderFieldName),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendor is the resolver for the updateVendor field.
|
|
func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionVendorUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Update(
|
|
ctx,
|
|
probo.UpdateVendorRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
StatusPageURL: gqlutils.UnwrapOmittable(input.StatusPageURL),
|
|
TermsOfServiceURL: gqlutils.UnwrapOmittable(input.TermsOfServiceURL),
|
|
PrivacyPolicyURL: gqlutils.UnwrapOmittable(input.PrivacyPolicyURL),
|
|
ServiceLevelAgreementURL: gqlutils.UnwrapOmittable(input.ServiceLevelAgreementURL),
|
|
DataProcessingAgreementURL: gqlutils.UnwrapOmittable(input.DataProcessingAgreementURL),
|
|
BusinessAssociateAgreementURL: gqlutils.UnwrapOmittable(input.BusinessAssociateAgreementURL),
|
|
SubprocessorsListURL: gqlutils.UnwrapOmittable(input.SubprocessorsListURL),
|
|
SecurityPageURL: gqlutils.UnwrapOmittable(input.SecurityPageURL),
|
|
TrustPageURL: gqlutils.UnwrapOmittable(input.TrustPageURL),
|
|
HeadquarterAddress: gqlutils.UnwrapOmittable(input.HeadquarterAddress),
|
|
LegalName: gqlutils.UnwrapOmittable(input.LegalName),
|
|
WebsiteURL: gqlutils.UnwrapOmittable(input.WebsiteURL),
|
|
Category: input.Category,
|
|
Certifications: input.Certifications,
|
|
BusinessOwnerID: gqlutils.UnwrapOmittable(input.BusinessOwnerID),
|
|
SecurityOwnerID: gqlutils.UnwrapOmittable(input.SecurityOwnerID),
|
|
ShowOnTrustCenter: input.ShowOnTrustCenter,
|
|
Countries: input.Countries,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateVendorPayload{
|
|
Vendor: types.NewVendor(vendor),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendor is the resolver for the deleteVendor field.
|
|
func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
err := prb.Vendors.Delete(ctx, input.VendorID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorPayload{
|
|
DeletedVendorID: input.VendorID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendorContact is the resolver for the createVendorContact field.
|
|
func (r *mutationResolver) CreateVendorContact(ctx context.Context, input types.CreateVendorContactInput) (*types.CreateVendorContactPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorContactCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
req := probo.CreateVendorContactRequest{
|
|
VendorID: input.VendorID,
|
|
FullName: input.FullName,
|
|
Email: input.Email,
|
|
Phone: input.Phone,
|
|
Role: input.Role,
|
|
}
|
|
|
|
vendorContact, err := prb.VendorContacts.Create(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create vendor contact", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateVendorContactPayload{
|
|
VendorContactEdge: types.NewVendorContactEdge(vendorContact, coredata.VendorContactOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendorContact is the resolver for the updateVendorContact field.
|
|
func (r *mutationResolver) UpdateVendorContact(ctx context.Context, input types.UpdateVendorContactInput) (*types.UpdateVendorContactPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionVendorContactUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateVendorContactRequest{
|
|
ID: input.ID,
|
|
FullName: gqlutils.UnwrapOmittable(input.FullName),
|
|
Email: gqlutils.UnwrapOmittable(input.Email),
|
|
Phone: gqlutils.UnwrapOmittable(input.Phone),
|
|
Role: gqlutils.UnwrapOmittable(input.Role),
|
|
}
|
|
|
|
vendorContact, err := prb.VendorContacts.Update(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update vendor contact", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateVendorContactPayload{
|
|
VendorContact: types.NewVendorContact(vendorContact),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorContact is the resolver for the deleteVendorContact field.
|
|
func (r *mutationResolver) DeleteVendorContact(ctx context.Context, input types.DeleteVendorContactInput) (*types.DeleteVendorContactPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorContactID, probo.ActionVendorContactDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorContactID.TenantID())
|
|
|
|
err := prb.VendorContacts.Delete(ctx, input.VendorContactID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor contact", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorContactPayload{
|
|
DeletedVendorContactID: input.VendorContactID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendorService is the resolver for the createVendorService field.
|
|
func (r *mutationResolver) CreateVendorService(ctx context.Context, input types.CreateVendorServiceInput) (*types.CreateVendorServicePayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorServiceCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
req := probo.CreateVendorServiceRequest{
|
|
VendorID: input.VendorID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
}
|
|
|
|
vendorService, err := prb.VendorServices.Create(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create vendor service", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateVendorServicePayload{
|
|
VendorServiceEdge: types.NewVendorServiceEdge(vendorService, coredata.VendorServiceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendorService is the resolver for the updateVendorService field.
|
|
func (r *mutationResolver) UpdateVendorService(ctx context.Context, input types.UpdateVendorServiceInput) (*types.UpdateVendorServicePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionVendorServiceUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateVendorServiceRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
}
|
|
|
|
vendorService, err := prb.VendorServices.Update(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update vendor service", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateVendorServicePayload{
|
|
VendorService: types.NewVendorService(vendorService),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorService is the resolver for the deleteVendorService field.
|
|
func (r *mutationResolver) DeleteVendorService(ctx context.Context, input types.DeleteVendorServiceInput) (*types.DeleteVendorServicePayload, error) {
|
|
if err := r.authorize(ctx, input.VendorServiceID, probo.ActionVendorServiceDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorServiceID.TenantID())
|
|
|
|
err := prb.VendorServices.Delete(ctx, input.VendorServiceID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor service", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorServicePayload{
|
|
DeletedVendorServiceID: input.VendorServiceID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateFramework is the resolver for the createFramework field.
|
|
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFrameworkCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
framework, err := prb.Frameworks.Create(
|
|
ctx,
|
|
probo.CreateFrameworkRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateFrameworkPayload{
|
|
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateFramework is the resolver for the updateFramework field.
|
|
func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionFrameworkUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
framework, err := prb.Frameworks.Update(
|
|
ctx,
|
|
probo.UpdateFrameworkRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateFrameworkPayload{
|
|
Framework: types.NewFramework(framework),
|
|
}, nil
|
|
}
|
|
|
|
// ImportFramework is the resolver for the importFramework field.
|
|
func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFrameworkImport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.ImportFrameworkRequest{}
|
|
if err := json.NewDecoder(input.File.File).Decode(&req.Framework); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot decode framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
framework, err := prb.Frameworks.Import(ctx, input.OrganizationID, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot import framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ImportFrameworkPayload{
|
|
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteFramework is the resolver for the deleteFramework field.
|
|
func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
|
|
|
|
err := prb.Frameworks.Delete(ctx, input.FrameworkID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete framework", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteFrameworkPayload{
|
|
DeletedFrameworkID: input.FrameworkID,
|
|
}, nil
|
|
}
|
|
|
|
// ExportFramework is the resolver for the exportFramework field.
|
|
func (r *mutationResolver) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) {
|
|
if err := r.authorize(ctx, input.FrameworkID, probo.ActionFrameworkExport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
exportJob, exportErr := prb.Frameworks.RequestExport(
|
|
ctx,
|
|
input.FrameworkID,
|
|
identity.EmailAddress,
|
|
identity.FullName,
|
|
)
|
|
if exportErr != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot export framework", log.Error(exportErr))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportFrameworkPayload{
|
|
ExportJobID: exportJob.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControl is the resolver for the createControl field.
|
|
func (r *mutationResolver) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) {
|
|
if err := r.authorize(ctx, input.FrameworkID, probo.ActionControlCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FrameworkID.TenantID())
|
|
|
|
control, err := prb.Controls.Create(
|
|
ctx,
|
|
probo.CreateControlRequest{
|
|
FrameworkID: input.FrameworkID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
SectionTitle: input.SectionTitle,
|
|
BestPractice: input.BestPractice,
|
|
Implemented: input.Implemented,
|
|
NotImplementedJustification: input.NotImplementedJustification,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create control", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateControl is the resolver for the updateControl field.
|
|
func (r *mutationResolver) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionControlUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
control, err := prb.Controls.Update(
|
|
ctx,
|
|
probo.UpdateControlRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
SectionTitle: input.SectionTitle,
|
|
BestPractice: input.BestPractice,
|
|
Implemented: input.Implemented,
|
|
NotImplementedJustification: gqlutils.UnwrapOmittable(input.NotImplementedJustification),
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update control", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateControlPayload{
|
|
Control: types.NewControl(control),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControl is the resolver for the deleteControl field.
|
|
func (r *mutationResolver) DeleteControl(ctx context.Context, input types.DeleteControlInput) (*types.DeleteControlPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ControlID.TenantID())
|
|
|
|
err := prb.Controls.Delete(ctx, input.ControlID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlPayload{
|
|
DeletedControlID: input.ControlID,
|
|
}, nil
|
|
}
|
|
|
|
// // CreateMeasure is the resolver for the createMeasure field.
|
|
func (r *mutationResolver) CreateMeasure(ctx context.Context, input types.CreateMeasureInput) (*types.CreateMeasurePayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeasureCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
measure, err := prb.Measures.Create(
|
|
ctx,
|
|
probo.CreateMeasureRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateMeasurePayload{
|
|
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMeasure is the resolver for the updateMeasure field.
|
|
func (r *mutationResolver) UpdateMeasure(ctx context.Context, input types.UpdateMeasureInput) (*types.UpdateMeasurePayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionMeasureUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
measure, err := prb.Measures.Update(
|
|
ctx,
|
|
probo.UpdateMeasureRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
Category: input.Category,
|
|
State: input.State,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateMeasurePayload{
|
|
Measure: types.NewMeasure(measure),
|
|
}, nil
|
|
}
|
|
|
|
// ImportMeasure is the resolver for the importMeasure field.
|
|
func (r *mutationResolver) ImportMeasure(ctx context.Context, input types.ImportMeasureInput) (*types.ImportMeasurePayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeasureImport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
var req probo.ImportMeasureRequest
|
|
if err := json.NewDecoder(input.File.File).Decode(&req.Measures); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot unmarshal measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
measures, err := prb.Measures.Import(ctx, input.OrganizationID, req)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot import measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
measureEdges := make([]*types.MeasureEdge, len(measures.Data))
|
|
for i, measure := range measures.Data {
|
|
measureEdges[i] = types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt)
|
|
}
|
|
|
|
return &types.ImportMeasurePayload{
|
|
MeasureEdges: measureEdges,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMeasure is the resolver for the deleteMeasure field.
|
|
func (r *mutationResolver) DeleteMeasure(ctx context.Context, input types.DeleteMeasureInput) (*types.DeleteMeasurePayload, error) {
|
|
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
err := prb.Measures.Delete(ctx, input.MeasureID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteMeasurePayload{
|
|
DeletedMeasureID: input.MeasureID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlMeasureMapping is the resolver for the createControlMeasureMapping field.
|
|
func (r *mutationResolver) CreateControlMeasureMapping(ctx context.Context, input types.CreateControlMeasureMappingInput) (*types.CreateControlMeasureMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlMeasureMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
control, measure, err := prb.Controls.CreateMeasureMapping(ctx, input.ControlID, input.MeasureID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create control measure mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlMeasureMappingPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlDocumentMapping is the resolver for the createControlDocumentMapping field.
|
|
func (r *mutationResolver) CreateControlDocumentMapping(ctx context.Context, input types.CreateControlDocumentMappingInput) (*types.CreateControlDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlDocumentMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
control, document, err := prb.Controls.CreateDocumentMapping(ctx, input.ControlID, input.DocumentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot create control document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlDocumentMappingPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlMeasureMapping is the resolver for the deleteControlMeasureMapping field.
|
|
func (r *mutationResolver) DeleteControlMeasureMapping(ctx context.Context, input types.DeleteControlMeasureMappingInput) (*types.DeleteControlMeasureMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlMeasureMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
control, measure, err := prb.Controls.DeleteMeasureMapping(ctx, input.ControlID, input.MeasureID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control measure mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlMeasureMappingPayload{
|
|
DeletedControlID: control.ID,
|
|
DeletedMeasureID: measure.ID,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlDocumentMapping is the resolver for the deleteControlDocumentMapping field.
|
|
func (r *mutationResolver) DeleteControlDocumentMapping(ctx context.Context, input types.DeleteControlDocumentMappingInput) (*types.DeleteControlDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlDocumentMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
control, document, err := prb.Controls.DeleteDocumentMapping(ctx, input.ControlID, input.DocumentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlDocumentMappingPayload{
|
|
DeletedControlID: control.ID,
|
|
DeletedDocumentID: document.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateApplicabilityStatement is the resolver for the createApplicabilityStatement field.
|
|
func (r *mutationResolver) CreateApplicabilityStatement(ctx context.Context, input types.CreateApplicabilityStatementInput) (*types.CreateApplicabilityStatementPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionApplicabilityStatementCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
|
|
|
applicabilityStatement, err := prb.StatementsOfApplicability.CreateApplicabilityStatement(ctx, input.StatementOfApplicabilityID, input.ControlID, input.Applicability, input.Justification)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create applicability statement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateApplicabilityStatementPayload{
|
|
ApplicabilityStatementEdge: types.NewApplicabilityStatementEdge(applicabilityStatement, coredata.ApplicabilityStatementOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateApplicabilityStatement is the resolver for the updateApplicabilityStatement field.
|
|
func (r *mutationResolver) UpdateApplicabilityStatement(ctx context.Context, input types.UpdateApplicabilityStatementInput) (*types.UpdateApplicabilityStatementPayload, error) {
|
|
if err := r.authorize(ctx, input.ApplicabilityStatementID, probo.ActionApplicabilityStatementUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
|
|
|
applicabilityStatement, err := prb.StatementsOfApplicability.UpdateApplicabilityStatement(ctx, input.ApplicabilityStatementID, input.Applicability, input.Justification)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot update applicability statement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateApplicabilityStatementPayload{
|
|
ApplicabilityStatement: types.NewApplicabilityStatement(applicabilityStatement),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteApplicabilityStatement is the resolver for the deleteApplicabilityStatement field.
|
|
func (r *mutationResolver) DeleteApplicabilityStatement(ctx context.Context, input types.DeleteApplicabilityStatementInput) (*types.DeleteApplicabilityStatementPayload, error) {
|
|
if err := r.authorize(ctx, input.ApplicabilityStatementID, probo.ActionApplicabilityStatementDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
|
|
|
err := prb.StatementsOfApplicability.DeleteApplicabilityStatement(ctx, input.ApplicabilityStatementID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete applicability statement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteApplicabilityStatementPayload{
|
|
DeletedApplicabilityStatementID: input.ApplicabilityStatementID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlAuditMapping is the resolver for the createControlAuditMapping field.
|
|
func (r *mutationResolver) CreateControlAuditMapping(ctx context.Context, input types.CreateControlAuditMappingInput) (*types.CreateControlAuditMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlAuditMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
|
|
|
control, audit, err := prb.Controls.CreateAuditMapping(ctx, input.ControlID, input.AuditID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create control audit mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlAuditMappingPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlAuditMapping is the resolver for the deleteControlAuditMapping field.
|
|
func (r *mutationResolver) DeleteControlAuditMapping(ctx context.Context, input types.DeleteControlAuditMappingInput) (*types.DeleteControlAuditMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlAuditMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
|
|
|
control, audit, err := prb.Controls.DeleteAuditMapping(ctx, input.ControlID, input.AuditID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control audit mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlAuditMappingPayload{
|
|
DeletedControlID: &control.ID,
|
|
DeletedAuditID: &audit.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlObligationMapping is the resolver for the createControlObligationMapping field.
|
|
func (r *mutationResolver) CreateControlObligationMapping(ctx context.Context, input types.CreateControlObligationMappingInput) (*types.CreateControlObligationMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlObligationMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ObligationID.TenantID())
|
|
|
|
control, obligation, err := prb.Controls.CreateObligationMapping(ctx, input.ControlID, input.ObligationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create control obligation mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlObligationMappingPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
ObligationEdge: types.NewObligationEdge(obligation, coredata.ObligationOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlObligationMapping is the resolver for the deleteControlObligationMapping field.
|
|
func (r *mutationResolver) DeleteControlObligationMapping(ctx context.Context, input types.DeleteControlObligationMappingInput) (*types.DeleteControlObligationMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlObligationMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ObligationID.TenantID())
|
|
|
|
control, obligation, err := prb.Controls.DeleteObligationMapping(ctx, input.ControlID, input.ObligationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control obligation mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlObligationMappingPayload{
|
|
DeletedControlID: control.ID,
|
|
DeletedObligationID: obligation.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlSnapshotMapping is the resolver for the createControlSnapshotMapping field.
|
|
func (r *mutationResolver) CreateControlSnapshotMapping(ctx context.Context, input types.CreateControlSnapshotMappingInput) (*types.CreateControlSnapshotMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlSnapshotMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.SnapshotID.TenantID())
|
|
|
|
control, snapshot, err := prb.Controls.CreateSnapshotMapping(ctx, input.ControlID, input.SnapshotID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create control snapshot mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateControlSnapshotMappingPayload{
|
|
ControlEdge: types.NewControlEdge(control, coredata.ControlOrderFieldCreatedAt),
|
|
SnapshotEdge: types.NewSnapshotEdge(snapshot, coredata.SnapshotOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlSnapshotMapping is the resolver for the deleteControlSnapshotMapping field.
|
|
func (r *mutationResolver) DeleteControlSnapshotMapping(ctx context.Context, input types.DeleteControlSnapshotMappingInput) (*types.DeleteControlSnapshotMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.ControlID, probo.ActionControlSnapshotMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.SnapshotID.TenantID())
|
|
|
|
control, snapshot, err := prb.Controls.DeleteSnapshotMapping(ctx, input.ControlID, input.SnapshotID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete control snapshot mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteControlSnapshotMappingPayload{
|
|
DeletedControlID: control.ID,
|
|
DeletedSnapshotID: snapshot.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateTask is the resolver for the createTask field.
|
|
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionTaskCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
task, err := prb.Tasks.Create(
|
|
ctx,
|
|
probo.CreateTaskRequest{
|
|
MeasureID: input.MeasureID,
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Priority: input.Priority,
|
|
TimeEstimate: input.TimeEstimate,
|
|
AssignedToID: input.AssignedToID,
|
|
Deadline: input.Deadline,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create task", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateTaskPayload{
|
|
TaskEdge: types.NewTaskEdge(task, coredata.TaskOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTask is the resolver for the updateTask field.
|
|
func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) {
|
|
if err := r.authorize(ctx, input.TaskID, probo.ActionTaskUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TaskID.TenantID())
|
|
|
|
task, err := prb.Tasks.Update(
|
|
ctx,
|
|
probo.UpdateTaskRequest{
|
|
TaskID: input.TaskID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
State: input.State,
|
|
Priority: input.Priority,
|
|
Rank: input.Rank,
|
|
TimeEstimate: gqlutils.UnwrapOmittable(input.TimeEstimate),
|
|
Deadline: gqlutils.UnwrapOmittable(input.Deadline),
|
|
AssignedToID: gqlutils.UnwrapOmittable(input.AssignedToID),
|
|
MeasureID: gqlutils.UnwrapOmittable(input.MeasureID),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update task", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTaskPayload{
|
|
Task: types.NewTask(task),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTask is the resolver for the deleteTask field.
|
|
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
|
|
if err := r.authorize(ctx, input.TaskID, probo.ActionTaskDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TaskID.TenantID())
|
|
|
|
err := prb.Tasks.Delete(ctx, input.TaskID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete task", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTaskPayload{
|
|
DeletedTaskID: input.TaskID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRisk is the resolver for the createRisk field.
|
|
func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionRiskCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
risk, err := prb.Risks.Create(
|
|
ctx,
|
|
probo.CreateRiskRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
Treatment: input.Treatment,
|
|
OwnerID: input.OwnerID,
|
|
InherentLikelihood: input.InherentLikelihood,
|
|
InherentImpact: input.InherentImpact,
|
|
ResidualLikelihood: input.ResidualLikelihood,
|
|
ResidualImpact: input.ResidualImpact,
|
|
Note: input.Note,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create risk", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateRiskPayload{
|
|
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateRisk is the resolver for the updateRisk field.
|
|
func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRiskInput) (*types.UpdateRiskPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionRiskUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
risk, err := prb.Risks.Update(
|
|
ctx,
|
|
probo.UpdateRiskRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
Category: input.Category,
|
|
Treatment: input.Treatment,
|
|
OwnerID: gqlutils.UnwrapOmittable(input.OwnerID),
|
|
InherentLikelihood: input.InherentLikelihood,
|
|
InherentImpact: input.InherentImpact,
|
|
ResidualLikelihood: input.ResidualLikelihood,
|
|
ResidualImpact: input.ResidualImpact,
|
|
Note: input.Note,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update risk", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateRiskPayload{
|
|
Risk: types.NewRisk(risk),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRisk is the resolver for the deleteRisk field.
|
|
func (r *mutationResolver) DeleteRisk(ctx context.Context, input types.DeleteRiskInput) (*types.DeleteRiskPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
err := prb.Risks.Delete(ctx, input.RiskID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete risk", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteRiskPayload{
|
|
DeletedRiskID: input.RiskID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRiskMeasureMapping is the resolver for the createRiskMeasureMapping field.
|
|
func (r *mutationResolver) CreateRiskMeasureMapping(ctx context.Context, input types.CreateRiskMeasureMappingInput) (*types.CreateRiskMeasureMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, measure, err := prb.Risks.CreateMeasureMapping(ctx, input.RiskID, input.MeasureID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create risk measure mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateRiskMeasureMappingPayload{
|
|
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
|
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRiskMeasureMapping is the resolver for the deleteRiskMeasureMapping field.
|
|
func (r *mutationResolver) DeleteRiskMeasureMapping(ctx context.Context, input types.DeleteRiskMeasureMappingInput) (*types.DeleteRiskMeasureMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, measure, err := prb.Risks.DeleteMeasureMapping(ctx, input.RiskID, input.MeasureID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete risk measure mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteRiskMeasureMappingPayload{
|
|
DeletedRiskID: risk.ID,
|
|
DeletedMeasureID: measure.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRiskDocumentMapping is the resolver for the createRiskDocumentMapping field.
|
|
func (r *mutationResolver) CreateRiskDocumentMapping(ctx context.Context, input types.CreateRiskDocumentMappingInput) (*types.CreateRiskDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, document, err := prb.Risks.CreateDocumentMapping(ctx, input.RiskID, input.DocumentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create risk document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateRiskDocumentMappingPayload{
|
|
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
|
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRiskDocumentMapping is the resolver for the deleteRiskDocumentMapping field.
|
|
func (r *mutationResolver) DeleteRiskDocumentMapping(ctx context.Context, input types.DeleteRiskDocumentMappingInput) (*types.DeleteRiskDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, document, err := prb.Risks.DeleteDocumentMapping(ctx, input.RiskID, input.DocumentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete risk document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteRiskDocumentMappingPayload{
|
|
DeletedRiskID: risk.ID,
|
|
DeletedDocumentID: document.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateMeasureDocumentMapping is the resolver for the createMeasureDocumentMapping field.
|
|
func (r *mutationResolver) CreateMeasureDocumentMapping(ctx context.Context, input types.CreateMeasureDocumentMappingInput) (*types.CreateMeasureDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
measure, document, err := prb.Measures.CreateDocumentMapping(ctx, input.MeasureID, input.DocumentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot create measure document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateMeasureDocumentMappingPayload{
|
|
MeasureEdge: types.NewMeasureEdge(measure, coredata.MeasureOrderFieldCreatedAt),
|
|
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMeasureDocumentMapping is the resolver for the deleteMeasureDocumentMapping field.
|
|
func (r *mutationResolver) DeleteMeasureDocumentMapping(ctx context.Context, input types.DeleteMeasureDocumentMappingInput) (*types.DeleteMeasureDocumentMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
measure, document, err := prb.Measures.DeleteDocumentMapping(ctx, input.MeasureID, input.DocumentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete measure document mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteMeasureDocumentMappingPayload{
|
|
DeletedMeasureID: measure.ID,
|
|
DeletedDocumentID: document.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRiskObligationMapping is the resolver for the createRiskObligationMapping field.
|
|
func (r *mutationResolver) CreateRiskObligationMapping(ctx context.Context, input types.CreateRiskObligationMappingInput) (*types.CreateRiskObligationMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, obligation, err := prb.Risks.CreateObligationMapping(ctx, input.RiskID, input.ObligationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create risk obligation mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateRiskObligationMappingPayload{
|
|
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
|
ObligationEdge: types.NewObligationEdge(obligation, coredata.ObligationOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRiskObligationMapping is the resolver for the deleteRiskObligationMapping field.
|
|
func (r *mutationResolver) DeleteRiskObligationMapping(ctx context.Context, input types.DeleteRiskObligationMappingInput) (*types.DeleteRiskObligationMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RiskID.TenantID())
|
|
|
|
risk, obligation, err := prb.Risks.DeleteObligationMapping(ctx, input.RiskID, input.ObligationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete risk obligation mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteRiskObligationMappingPayload{
|
|
DeletedRiskID: risk.ID,
|
|
DeletedObligationID: obligation.ID,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteEvidence is the resolver for the deleteEvidence field.
|
|
func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) {
|
|
if err := r.authorize(ctx, input.EvidenceID, probo.ActionEvidenceDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.EvidenceID.TenantID())
|
|
|
|
err := prb.Evidences.Delete(ctx, input.EvidenceID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete evidence", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteEvidencePayload{
|
|
DeletedEvidenceID: input.EvidenceID,
|
|
}, nil
|
|
}
|
|
|
|
// UploadMeasureEvidence is the resolver for the uploadMeasureEvidence field.
|
|
func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input types.UploadMeasureEvidenceInput) (*types.UploadMeasureEvidencePayload, error) {
|
|
if err := r.authorize(ctx, input.MeasureID, probo.ActionMeasureEvidenceUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeasureID.TenantID())
|
|
|
|
evidence, err := prb.Evidences.UploadMeasureEvidence(
|
|
ctx,
|
|
probo.UploadMeasureEvidenceRequest{
|
|
MeasureID: input.MeasureID,
|
|
File: probo.FileUpload{
|
|
Content: input.File.File,
|
|
Filename: input.File.Filename,
|
|
Size: input.File.Size,
|
|
ContentType: input.File.ContentType,
|
|
},
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload measure evidence", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadMeasureEvidencePayload{
|
|
EvidenceEdge: types.NewEvidenceEdge(evidence, coredata.EvidenceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UploadVendorComplianceReport is the resolver for the uploadVendorComplianceReport field.
|
|
func (r *mutationResolver) UploadVendorComplianceReport(ctx context.Context, input types.UploadVendorComplianceReportInput) (*types.UploadVendorComplianceReportPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorComplianceReportUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorComplianceReport, err := prb.VendorComplianceReports.Upload(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorComplianceReportCreateRequest{
|
|
File: probo.FileUpload{Filename: input.File.Filename, Size: input.File.Size, Content: input.File.File, ContentType: input.File.ContentType},
|
|
ReportDate: input.ReportDate,
|
|
ValidUntil: input.ValidUntil,
|
|
ReportName: input.ReportName,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload vendor compliance report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadVendorComplianceReportPayload{
|
|
VendorComplianceReportEdge: types.NewVendorComplianceReportEdge(vendorComplianceReport, coredata.VendorComplianceReportOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorComplianceReport is the resolver for the deleteVendorComplianceReport field.
|
|
func (r *mutationResolver) DeleteVendorComplianceReport(ctx context.Context, input types.DeleteVendorComplianceReportInput) (*types.DeleteVendorComplianceReportPayload, error) {
|
|
if err := r.authorize(ctx, input.ReportID, probo.ActionVendorComplianceReportDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ReportID.TenantID())
|
|
|
|
err := prb.VendorComplianceReports.Delete(ctx, input.ReportID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor compliance report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorComplianceReportPayload{
|
|
DeletedVendorComplianceReportID: input.ReportID,
|
|
}, nil
|
|
}
|
|
|
|
// UploadVendorBusinessAssociateAgreement is the resolver for the uploadVendorBusinessAssociateAgreement field.
|
|
func (r *mutationResolver) UploadVendorBusinessAssociateAgreement(ctx context.Context, input types.UploadVendorBusinessAssociateAgreementInput) (*types.UploadVendorBusinessAssociateAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorBusinessAssociateAgreement, file, err := prb.VendorBusinessAssociateAgreements.Upload(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorBusinessAssociateAgreementCreateRequest{
|
|
File: input.File.File,
|
|
ValidFrom: input.ValidFrom,
|
|
ValidUntil: input.ValidUntil,
|
|
FileName: input.FileName,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload vendor business associate agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadVendorBusinessAssociateAgreementPayload{
|
|
VendorBusinessAssociateAgreement: types.NewVendorBusinessAssociateAgreement(vendorBusinessAssociateAgreement, file),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendorBusinessAssociateAgreement is the resolver for the updateVendorBusinessAssociateAgreement field.
|
|
func (r *mutationResolver) UpdateVendorBusinessAssociateAgreement(ctx context.Context, input types.UpdateVendorBusinessAssociateAgreementInput) (*types.UpdateVendorBusinessAssociateAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorBusinessAssociateAgreement, file, err := prb.VendorBusinessAssociateAgreements.Update(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorBusinessAssociateAgreementUpdateRequest{
|
|
ValidFrom: gqlutils.UnwrapOmittable(input.ValidFrom),
|
|
ValidUntil: gqlutils.UnwrapOmittable(input.ValidUntil),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update vendor business associate agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateVendorBusinessAssociateAgreementPayload{
|
|
VendorBusinessAssociateAgreement: types.NewVendorBusinessAssociateAgreement(vendorBusinessAssociateAgreement, file),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorBusinessAssociateAgreement is the resolver for the deleteVendorBusinessAssociateAgreement field.
|
|
func (r *mutationResolver) DeleteVendorBusinessAssociateAgreement(ctx context.Context, input types.DeleteVendorBusinessAssociateAgreementInput) (*types.DeleteVendorBusinessAssociateAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
err := prb.VendorBusinessAssociateAgreements.DeleteByVendorID(ctx, input.VendorID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor business associate agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorBusinessAssociateAgreementPayload{
|
|
DeletedVendorID: input.VendorID,
|
|
}, nil
|
|
}
|
|
|
|
// UploadVendorDataPrivacyAgreement is the resolver for the uploadVendorDataPrivacyAgreement field.
|
|
func (r *mutationResolver) UploadVendorDataPrivacyAgreement(ctx context.Context, input types.UploadVendorDataPrivacyAgreementInput) (*types.UploadVendorDataPrivacyAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.Upload(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorDataPrivacyAgreementCreateRequest{
|
|
File: input.File.File,
|
|
ValidFrom: input.ValidFrom,
|
|
ValidUntil: input.ValidUntil,
|
|
FileName: input.FileName,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload vendor data privacy agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadVendorDataPrivacyAgreementPayload{
|
|
VendorDataPrivacyAgreement: types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendorDataPrivacyAgreement is the resolver for the updateVendorDataPrivacyAgreement field.
|
|
func (r *mutationResolver) UpdateVendorDataPrivacyAgreement(ctx context.Context, input types.UpdateVendorDataPrivacyAgreementInput) (*types.UpdateVendorDataPrivacyAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.Update(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorDataPrivacyAgreementUpdateRequest{
|
|
ValidFrom: gqlutils.UnwrapOmittable(input.ValidFrom),
|
|
ValidUntil: gqlutils.UnwrapOmittable(input.ValidUntil),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update vendor data privacy agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateVendorDataPrivacyAgreementPayload{
|
|
VendorDataPrivacyAgreement: types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorDataPrivacyAgreement is the resolver for the deleteVendorDataPrivacyAgreement field.
|
|
func (r *mutationResolver) DeleteVendorDataPrivacyAgreement(ctx context.Context, input types.DeleteVendorDataPrivacyAgreementInput) (*types.DeleteVendorDataPrivacyAgreementPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
err := prb.VendorDataPrivacyAgreements.DeleteByVendorID(ctx, input.VendorID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete vendor data privacy agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteVendorDataPrivacyAgreementPayload{
|
|
DeletedVendorID: input.VendorID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateDocument is the resolver for the createDocument field.
|
|
func (r *mutationResolver) CreateDocument(ctx context.Context, input types.CreateDocumentInput) (*types.CreateDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDocumentCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
var content string
|
|
if input.Content != nil {
|
|
content = *input.Content
|
|
}
|
|
|
|
document, documentVersion, err := prb.Documents.Create(
|
|
ctx,
|
|
probo.CreateDocumentRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Title: input.Title,
|
|
Content: content,
|
|
Classification: input.Classification,
|
|
DocumentType: input.DocumentType,
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
DefaultApproverIDs: input.DefaultApproverIds,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDocumentPayload{
|
|
DocumentEdge: types.NewDocumentEdge(document, coredata.DocumentOrderFieldTitle),
|
|
DocumentVersionEdge: types.NewDocumentVersionEdge(documentVersion, coredata.DocumentVersionOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDocument is the resolver for the updateDocument field.
|
|
func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.UpdateDocumentInput) (*types.UpdateDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionDocumentUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
var defaultApproverIDs *[]gid.GID
|
|
if input.DefaultApproverIds != nil {
|
|
defaultApproverIDs = &input.DefaultApproverIds
|
|
}
|
|
|
|
document, err := prb.Documents.Update(
|
|
ctx,
|
|
probo.UpdateDocumentRequest{
|
|
DocumentID: input.ID,
|
|
Title: input.Title,
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
DefaultApproverIDs: defaultApproverIDs,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateDocumentPayload{
|
|
Document: types.NewDocument(document),
|
|
}, nil
|
|
}
|
|
|
|
// ArchiveDocument is the resolver for the archiveDocument field.
|
|
func (r *mutationResolver) ArchiveDocument(ctx context.Context, input types.ArchiveDocumentInput) (*types.ArchiveDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentArchive); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
document, err := prb.Documents.Archive(ctx, input.DocumentID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot archive document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ArchiveDocumentPayload{
|
|
Document: types.NewDocument(document),
|
|
}, nil
|
|
}
|
|
|
|
// UnarchiveDocument is the resolver for the unarchiveDocument field.
|
|
func (r *mutationResolver) UnarchiveDocument(ctx context.Context, input types.UnarchiveDocumentInput) (*types.UnarchiveDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentUnarchive); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
document, err := prb.Documents.Unarchive(ctx, input.DocumentID)
|
|
if err != nil {
|
|
if errNotArchived, ok := errors.AsType[*probo.ErrDocumentNotArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errNotArchived)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot unarchive document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UnarchiveDocumentPayload{
|
|
Document: types.NewDocument(document),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteDocument is the resolver for the deleteDocument field.
|
|
func (r *mutationResolver) DeleteDocument(ctx context.Context, input types.DeleteDocumentInput) (*types.DeleteDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
err := prb.Documents.SoftDelete(ctx, input.DocumentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot soft delete document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteDocumentPayload{
|
|
DeletedDocumentID: input.DocumentID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateMeeting is the resolver for the createMeeting field.
|
|
func (r *mutationResolver) CreateMeeting(ctx context.Context, input types.CreateMeetingInput) (*types.CreateMeetingPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionMeetingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
meeting, err := prb.Meetings.Create(
|
|
ctx,
|
|
probo.CreateMeetingRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Date: input.Date,
|
|
AttendeeIDs: input.AttendeeIds,
|
|
Minutes: input.Minutes,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create meeting", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateMeetingPayload{
|
|
MeetingEdge: types.NewMeetingEdge(meeting, coredata.MeetingOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMeeting is the resolver for the updateMeeting field.
|
|
func (r *mutationResolver) UpdateMeeting(ctx context.Context, input types.UpdateMeetingInput) (*types.UpdateMeetingPayload, error) {
|
|
if err := r.authorize(ctx, input.MeetingID, probo.ActionMeetingUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeetingID.TenantID())
|
|
|
|
var attendeeIDs []gid.GID
|
|
if input.AttendeeIds != nil {
|
|
attendeeIDs = input.AttendeeIds
|
|
}
|
|
|
|
meeting, err := prb.Meetings.Update(
|
|
ctx,
|
|
probo.UpdateMeetingRequest{
|
|
MeetingID: input.MeetingID,
|
|
Name: input.Name,
|
|
Date: input.Date,
|
|
AttendeeIDs: attendeeIDs,
|
|
Minutes: gqlutils.UnwrapOmittable(input.Minutes),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update meeting", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateMeetingPayload{
|
|
Meeting: types.NewMeeting(meeting),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMeeting is the resolver for the deleteMeeting field.
|
|
func (r *mutationResolver) DeleteMeeting(ctx context.Context, input types.DeleteMeetingInput) (*types.DeleteMeetingPayload, error) {
|
|
if err := r.authorize(ctx, input.MeetingID, probo.ActionMeetingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.MeetingID.TenantID())
|
|
|
|
err := prb.Meetings.Delete(ctx, input.MeetingID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete meeting", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteMeetingPayload{
|
|
DeletedMeetingID: input.MeetingID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateWebhookSubscription is the resolver for the createWebhookSubscription field.
|
|
func (r *mutationResolver) CreateWebhookSubscription(ctx context.Context, input types.CreateWebhookSubscriptionInput) (*types.CreateWebhookSubscriptionPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
wc, err := prb.WebhookSubscriptions.Create(
|
|
ctx,
|
|
probo.CreateWebhookSubscriptionRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
EndpointURL: input.EndpointURL,
|
|
SelectedEvents: input.SelectedEvents,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create webhook subscription", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateWebhookSubscriptionPayload{
|
|
WebhookSubscriptionEdge: types.NewWebhookSubscriptionEdge(wc, coredata.WebhookSubscriptionOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateWebhookSubscription is the resolver for the updateWebhookSubscription field.
|
|
func (r *mutationResolver) UpdateWebhookSubscription(ctx context.Context, input types.UpdateWebhookSubscriptionInput) (*types.UpdateWebhookSubscriptionPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionWebhookSubscriptionUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
wc, err := prb.WebhookSubscriptions.Update(
|
|
ctx,
|
|
probo.UpdateWebhookSubscriptionRequest{
|
|
WebhookSubscriptionID: input.ID,
|
|
EndpointURL: input.EndpointURL,
|
|
SelectedEvents: input.SelectedEvents,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update webhook subscription", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateWebhookSubscriptionPayload{
|
|
WebhookSubscription: types.NewWebhookSubscription(wc),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteWebhookSubscription is the resolver for the deleteWebhookSubscription field.
|
|
func (r *mutationResolver) DeleteWebhookSubscription(ctx context.Context, input types.DeleteWebhookSubscriptionInput) (*types.DeleteWebhookSubscriptionPayload, error) {
|
|
if err := r.authorize(ctx, input.WebhookSubscriptionID, probo.ActionWebhookSubscriptionDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.WebhookSubscriptionID.TenantID())
|
|
|
|
err := prb.WebhookSubscriptions.Delete(ctx, input.WebhookSubscriptionID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete webhook subscription", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteWebhookSubscriptionPayload{
|
|
DeletedWebhookSubscriptionID: input.WebhookSubscriptionID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateStatementOfApplicability is the resolver for the createStatementOfApplicability field.
|
|
func (r *mutationResolver) CreateStatementOfApplicability(ctx context.Context, input types.CreateStatementOfApplicabilityInput) (*types.CreateStatementOfApplicabilityPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
statementOfApplicability, err := prb.StatementsOfApplicability.Create(
|
|
ctx,
|
|
probo.CreateStatementOfApplicabilityRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
OwnerID: input.OwnerID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create statement_of_applicability", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateStatementOfApplicabilityPayload{
|
|
StatementOfApplicabilityEdge: types.NewStatementOfApplicabilityEdge(statementOfApplicability, coredata.StatementOfApplicabilityOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateStatementOfApplicability is the resolver for the updateStatementOfApplicability field.
|
|
func (r *mutationResolver) UpdateStatementOfApplicability(ctx context.Context, input types.UpdateStatementOfApplicabilityInput) (*types.UpdateStatementOfApplicabilityPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
var name *string
|
|
if input.Name != nil {
|
|
name = input.Name
|
|
}
|
|
|
|
statementOfApplicability, err := prb.StatementsOfApplicability.Update(
|
|
ctx,
|
|
probo.UpdateStatementOfApplicabilityRequest{
|
|
StatementOfApplicabilityID: input.ID,
|
|
Name: name,
|
|
OwnerID: input.OwnerID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update statement_of_applicability", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateStatementOfApplicabilityPayload{
|
|
StatementOfApplicability: types.NewStatementOfApplicability(statementOfApplicability),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteStatementOfApplicability is the resolver for the deleteStatementOfApplicability field.
|
|
func (r *mutationResolver) DeleteStatementOfApplicability(ctx context.Context, input types.DeleteStatementOfApplicabilityInput) (*types.DeleteStatementOfApplicabilityPayload, error) {
|
|
if err := r.authorize(ctx, input.StatementOfApplicabilityID, probo.ActionStatementOfApplicabilityDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
|
|
|
err := prb.StatementsOfApplicability.Delete(ctx, input.StatementOfApplicabilityID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete statement_of_applicability", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteStatementOfApplicabilityPayload{
|
|
DeletedStatementOfApplicabilityID: input.StatementOfApplicabilityID,
|
|
}, nil
|
|
}
|
|
|
|
// ExportStatementOfApplicabilityPDF is the resolver for the exportStatementOfApplicabilityPDF field.
|
|
func (r *mutationResolver) ExportStatementOfApplicabilityPDF(ctx context.Context, input types.ExportStatementOfApplicabilityPDFInput) (*types.ExportStatementOfApplicabilityPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.StatementOfApplicabilityID, probo.ActionStatementOfApplicabilityExport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
|
|
|
pdfData, err := prb.StatementsOfApplicability.ExportPDF(ctx, input.StatementOfApplicabilityID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot export statement of applicability PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
base64Data := base64.StdEncoding.EncodeToString(pdfData)
|
|
dataURI := fmt.Sprintf("data:application/pdf;base64,%s", base64Data)
|
|
|
|
return &types.ExportStatementOfApplicabilityPDFPayload{
|
|
Data: dataURI,
|
|
}, nil
|
|
}
|
|
|
|
// PublishMajorDocumentVersion is the resolver for the publishMajorDocumentVersion field.
|
|
func (r *mutationResolver) PublishMajorDocumentVersion(ctx context.Context, input types.PublishMajorDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
document, documentVersion, err := prb.Documents.PublishMajorVersion(
|
|
ctx,
|
|
input.DocumentID,
|
|
authn.IdentityFromContext(ctx).ID,
|
|
input.Changelog,
|
|
)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotDraft)
|
|
}
|
|
|
|
if errPending, ok := errors.AsType[*probo.ErrDocumentVersionPendingApproval](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errPending)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot publish major document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.PublishDocumentVersionPayload{
|
|
Document: types.NewDocument(document),
|
|
DocumentVersion: types.NewDocumentVersion(documentVersion),
|
|
}, nil
|
|
}
|
|
|
|
// PublishMinorDocumentVersion is the resolver for the publishMinorDocumentVersion field.
|
|
func (r *mutationResolver) PublishMinorDocumentVersion(ctx context.Context, input types.PublishMinorDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
document, documentVersion, err := prb.Documents.PublishMinorVersion(
|
|
ctx,
|
|
input.DocumentID,
|
|
authn.IdentityFromContext(ctx).ID,
|
|
input.Changelog,
|
|
)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotDraft)
|
|
}
|
|
|
|
if errPending, ok := errors.AsType[*probo.ErrDocumentVersionPendingApproval](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errPending)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot publish minor document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.PublishDocumentVersionPayload{
|
|
Document: types.NewDocument(document),
|
|
DocumentVersion: types.NewDocumentVersion(documentVersion),
|
|
}, nil
|
|
}
|
|
|
|
// BulkPublishMajorDocumentVersions is the resolver for the bulkPublishMajorDocumentVersions field.
|
|
func (r *mutationResolver) BulkPublishMajorDocumentVersions(ctx context.Context, input types.BulkPublishDocumentVersionsInput) (*types.BulkPublishDocumentVersionsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkPublishDocumentVersionsPayload{
|
|
DocumentVersions: []*types.DocumentVersion{},
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentVersionPublish); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
versions, documents, err := prb.DocumentApprovals.BulkPublishMajorVersions(ctx, probo.BulkPublishVersionsRequest{
|
|
DocumentIDs: input.DocumentIds,
|
|
Changelog: input.Changelog,
|
|
})
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotDraft)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot bulk publish major document versions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
typesVersions := make([]*types.DocumentVersion, len(versions))
|
|
for i, v := range versions {
|
|
typesVersions[i] = types.NewDocumentVersion(v)
|
|
}
|
|
|
|
typesDocuments := make([]*types.Document, len(documents))
|
|
for i, d := range documents {
|
|
typesDocuments[i] = types.NewDocument(d)
|
|
}
|
|
|
|
return &types.BulkPublishDocumentVersionsPayload{
|
|
DocumentVersions: typesVersions,
|
|
Documents: typesDocuments,
|
|
}, nil
|
|
}
|
|
|
|
// BulkPublishMinorDocumentVersions is the resolver for the bulkPublishMinorDocumentVersions field.
|
|
func (r *mutationResolver) BulkPublishMinorDocumentVersions(ctx context.Context, input types.BulkPublishDocumentVersionsInput) (*types.BulkPublishDocumentVersionsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkPublishDocumentVersionsPayload{
|
|
DocumentVersions: []*types.DocumentVersion{},
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentVersionPublish); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
versions, documents, err := prb.Documents.BulkPublishMinorVersions(ctx, probo.BulkPublishVersionsRequest{
|
|
DocumentIDs: input.DocumentIds,
|
|
Changelog: input.Changelog,
|
|
})
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotDraft)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot bulk publish minor document versions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
typesVersions := make([]*types.DocumentVersion, len(versions))
|
|
for i, v := range versions {
|
|
typesVersions[i] = types.NewDocumentVersion(v)
|
|
}
|
|
|
|
typesDocuments := make([]*types.Document, len(documents))
|
|
for i, d := range documents {
|
|
typesDocuments[i] = types.NewDocument(d)
|
|
}
|
|
|
|
return &types.BulkPublishDocumentVersionsPayload{
|
|
DocumentVersions: typesVersions,
|
|
Documents: typesDocuments,
|
|
}, nil
|
|
}
|
|
|
|
// RequestDocumentVersionApproval is the resolver for the requestDocumentVersionApproval field.
|
|
func (r *mutationResolver) RequestDocumentVersionApproval(ctx context.Context, input types.RequestDocumentVersionApprovalInput) (*types.RequestDocumentVersionApprovalPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentVersionRequestApproval); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
quorum, err := prb.DocumentApprovals.RequestApproval(ctx, probo.RequestApprovalRequest{
|
|
DocumentID: input.DocumentID,
|
|
ApproverIDs: input.ApproverIds,
|
|
Changelog: input.Changelog,
|
|
})
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errNotDraft)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot request document version approval", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RequestDocumentVersionApprovalPayload{
|
|
ApprovalQuorum: types.NewDocumentVersionApprovalQuorum(quorum),
|
|
}, nil
|
|
}
|
|
|
|
// VoidDocumentVersionApproval is the resolver for the voidDocumentVersionApproval field.
|
|
func (r *mutationResolver) VoidDocumentVersionApproval(ctx context.Context, input types.VoidDocumentVersionApprovalInput) (*types.VoidDocumentVersionApprovalPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionVoidApproval); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
quorum, documentVersion, err := prb.DocumentApprovals.VoidApproval(ctx, input.DocumentVersionID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotPending, ok := errors.AsType[*probo.ErrDocumentVersionNotPendingApproval](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errNotPending)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot void document version approval", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.VoidDocumentVersionApprovalPayload{
|
|
ApprovalQuorum: types.NewDocumentVersionApprovalQuorum(quorum),
|
|
DocumentVersion: types.NewDocumentVersion(documentVersion),
|
|
}, nil
|
|
}
|
|
|
|
// BulkDeleteDocuments is the resolver for the bulkDeleteDocuments field.
|
|
func (r *mutationResolver) BulkDeleteDocuments(ctx context.Context, input types.BulkDeleteDocumentsInput) (*types.BulkDeleteDocumentsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkDeleteDocumentsPayload{
|
|
DeletedDocumentIds: []gid.GID{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
err := prb.Documents.BulkSoftDelete(ctx, input.DocumentIds)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot bulk delete documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.BulkDeleteDocumentsPayload{
|
|
DeletedDocumentIds: input.DocumentIds,
|
|
}, nil
|
|
}
|
|
|
|
// BulkArchiveDocuments is the resolver for the bulkArchiveDocuments field.
|
|
func (r *mutationResolver) BulkArchiveDocuments(ctx context.Context, input types.BulkArchiveDocumentsInput) (*types.BulkArchiveDocumentsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkArchiveDocumentsPayload{
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentArchive); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
if err := prb.Documents.BulkArchive(ctx, input.DocumentIds); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot bulk archive documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.BulkArchiveDocumentsPayload{
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
// BulkUnarchiveDocuments is the resolver for the bulkUnarchiveDocuments field.
|
|
func (r *mutationResolver) BulkUnarchiveDocuments(ctx context.Context, input types.BulkUnarchiveDocumentsInput) (*types.BulkUnarchiveDocumentsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkUnarchiveDocumentsPayload{
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentUnarchive); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
if err := prb.Documents.BulkUnarchive(ctx, input.DocumentIds); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot bulk unarchive documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.BulkUnarchiveDocumentsPayload{
|
|
Documents: []*types.Document{},
|
|
}, nil
|
|
}
|
|
|
|
// BulkExportDocuments is the resolver for the bulkExportDocuments field.
|
|
func (r *mutationResolver) BulkExportDocuments(ctx context.Context, input types.BulkExportDocumentsInput) (*types.BulkExportDocumentsPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
r.logger.ErrorCtx(ctx, "no document ids provided")
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// TODO have a way to batch authorize for resources
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentVersionExport); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
options := probo.ExportPDFOptions{
|
|
WithWatermark: input.WithWatermark,
|
|
WithSignatures: input.WithSignatures,
|
|
WatermarkEmail: input.WatermarkEmail,
|
|
}
|
|
|
|
documentExport, exportErr := prb.Documents.RequestExport(ctx, input.DocumentIds, identity.EmailAddress, identity.FullName, options)
|
|
if exportErr != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot request document export", log.Error(exportErr))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.BulkExportDocumentsPayload{
|
|
ExportJobID: documentExport.ID,
|
|
}, nil
|
|
}
|
|
|
|
// GenerateDocumentChangelog is the resolver for the generateDocumentChangelog field.
|
|
func (r *mutationResolver) GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentChangelogGenerate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
changelog, err := prb.Documents.GenerateChangelog(ctx, input.DocumentID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot generate document changelog", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.GenerateDocumentChangelogPayload{
|
|
Changelog: *changelog,
|
|
}, nil
|
|
}
|
|
|
|
// CreateDraftDocumentVersion is the resolver for the createDraftDocumentVersion field.
|
|
func (r *mutationResolver) CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentDraftVersionCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentID.TenantID())
|
|
|
|
documentVersion, err := prb.Documents.CreateDraft(ctx, input.DocumentID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotPublished, ok := errors.AsType[*probo.ErrDocumentVersionNotPublished](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errNotPublished)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot create draft document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDraftDocumentVersionPayload{
|
|
DocumentVersionEdge: types.NewDocumentVersionEdge(documentVersion, coredata.DocumentVersionOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteDraftDocumentVersion is the resolver for the deleteDraftDocumentVersion field.
|
|
func (r *mutationResolver) DeleteDraftDocumentVersion(ctx context.Context, input types.DeleteDraftDocumentVersionInput) (*types.DeleteDraftDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionDeleteDraft); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
err := prb.Documents.DeleteDraft(ctx, input.DocumentVersionID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot delete draft document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteDraftDocumentVersionPayload{
|
|
DeletedDocumentVersionID: input.DocumentVersionID,
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDocumentVersion is the resolver for the updateDocumentVersion field.
|
|
func (r *mutationResolver) UpdateDocumentVersion(ctx context.Context, input types.UpdateDocumentVersionInput) (*types.UpdateDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
documentVersion, err := prb.Documents.UpdateVersion(
|
|
ctx,
|
|
probo.UpdateDocumentVersionRequest{
|
|
ID: input.DocumentVersionID,
|
|
Content: input.Content,
|
|
Classification: input.Classification,
|
|
DocumentType: input.DocumentType,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errNotDraft)
|
|
}
|
|
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateDocumentVersionPayload{
|
|
DocumentVersion: types.NewDocumentVersion(documentVersion),
|
|
}, nil
|
|
}
|
|
|
|
// RequestSignature is the resolver for the requestSignature field.
|
|
func (r *mutationResolver) RequestSignature(ctx context.Context, input types.RequestSignatureInput) (*types.RequestSignaturePayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureRequest); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
documentVersionSignature, err := prb.Documents.RequestSignature(
|
|
ctx,
|
|
probo.RequestSignatureRequest{
|
|
DocumentVersionID: input.DocumentVersionID,
|
|
Signatory: input.SignatoryID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot request signature", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RequestSignaturePayload{
|
|
DocumentVersionSignatureEdge: types.NewDocumentVersionSignatureEdge(documentVersionSignature, coredata.DocumentVersionSignatureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// BulkRequestSignatures is the resolver for the bulkRequestSignatures field.
|
|
func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input types.BulkRequestSignaturesInput) (*types.BulkRequestSignaturesPayload, error) {
|
|
if len(input.DocumentIds) == 0 {
|
|
return &types.BulkRequestSignaturesPayload{
|
|
DocumentVersionSignatureEdges: []*types.DocumentVersionSignatureEdge{},
|
|
}, nil
|
|
}
|
|
|
|
for _, documentID := range input.DocumentIds {
|
|
if err := r.authorize(ctx, documentID, probo.ActionDocumentVersionSignatureRequest); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentIds[0].TenantID())
|
|
|
|
documentVersionSignatures, err := prb.Documents.BulkRequestSignatures(
|
|
ctx,
|
|
probo.BulkRequestSignaturesRequest{
|
|
DocumentIDs: input.DocumentIds,
|
|
SignatoryIDs: input.SignatoryIds,
|
|
},
|
|
)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot bulk request signatures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.BulkRequestSignaturesPayload{
|
|
DocumentVersionSignatureEdges: types.NewDocumentVersionSignatureEdges(documentVersionSignatures, coredata.DocumentVersionSignatureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// SendSigningNotifications is the resolver for the sendSigningNotifications field.
|
|
func (r *mutationResolver) SendSigningNotifications(ctx context.Context, input types.SendSigningNotificationsInput) (*types.SendSigningNotificationsPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDocumentSendSigningNotifications); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
err := prb.Documents.SendSigningNotifications(ctx, input.OrganizationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot send signing notifications", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.SendSigningNotificationsPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// CancelSignatureRequest is the resolver for the cancelSignatureRequest field.
|
|
func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input types.CancelSignatureRequestInput) (*types.CancelSignatureRequestPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionSignatureID, probo.ActionDocumentVersionCancelSignature); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionSignatureID.TenantID())
|
|
|
|
err := prb.Documents.CancelSignatureRequest(ctx, input.DocumentVersionSignatureID)
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot cancel signature request", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CancelSignatureRequestPayload{
|
|
DeletedDocumentVersionSignatureID: input.DocumentVersionSignatureID,
|
|
}, nil
|
|
}
|
|
|
|
// SignDocument is the resolver for the signDocument field.
|
|
func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDocumentInput) (*types.SignDocumentPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSign); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
documentVersionSignature, err := prb.Documents.SignDocumentVersionByIdentity(ctx, input.DocumentVersionID, identity.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot sign document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.SignDocumentPayload{
|
|
DocumentVersionSignature: types.NewDocumentVersionSignature(documentVersionSignature),
|
|
}, nil
|
|
}
|
|
|
|
// ApproveDocumentVersion is the resolver for the approveDocumentVersion field.
|
|
func (r *mutationResolver) ApproveDocumentVersion(ctx context.Context, input types.ApproveDocumentVersionInput) (*types.ApproveDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionApprove); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
httpReq := gqlutils.HTTPRequestFromContext(ctx)
|
|
|
|
signerIP, _, _ := net.SplitHostPort(httpReq.RemoteAddr)
|
|
if signerIP == "" {
|
|
signerIP = httpReq.RemoteAddr
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
decision, err := prb.DocumentApprovals.Approve(ctx, probo.ApproveDocumentVersionRequest{
|
|
DocumentVersionID: input.DocumentVersionID,
|
|
IdentityID: identity.ID,
|
|
Comment: input.Comment,
|
|
SignerFullName: identity.FullName,
|
|
SignerEmail: identity.EmailAddress,
|
|
SignerIPAddr: signerIP,
|
|
SignerUA: httpReq.UserAgent(),
|
|
})
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotPending, ok := errors.AsType[*probo.ErrDocumentVersionNotPendingApproval](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotPending)
|
|
}
|
|
|
|
if errAlready, ok := errors.AsType[*probo.ErrApprovalDecisionAlreadyMade](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errAlready)
|
|
}
|
|
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot approve document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ApproveDocumentVersionPayload{
|
|
ApprovalDecision: types.NewDocumentVersionApprovalDecision(decision),
|
|
}, nil
|
|
}
|
|
|
|
// RejectDocumentVersion is the resolver for the rejectDocumentVersion field.
|
|
func (r *mutationResolver) RejectDocumentVersion(ctx context.Context, input types.RejectDocumentVersionInput) (*types.RejectDocumentVersionPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionReject); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
decision, err := prb.DocumentApprovals.Reject(ctx, probo.RejectDocumentVersionRequest{
|
|
DocumentVersionID: input.DocumentVersionID,
|
|
IdentityID: identity.ID,
|
|
Comment: input.Comment,
|
|
})
|
|
if err != nil {
|
|
if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errArchived)
|
|
}
|
|
|
|
if errNotPending, ok := errors.AsType[*probo.ErrDocumentVersionNotPendingApproval](err); ok {
|
|
return nil, gqlutils.Invalid(ctx, errNotPending)
|
|
}
|
|
|
|
if errAlready, ok := errors.AsType[*probo.ErrApprovalDecisionAlreadyMade](err); ok {
|
|
return nil, gqlutils.Conflict(ctx, errAlready)
|
|
}
|
|
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot reject document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RejectDocumentVersionPayload{
|
|
ApprovalDecision: types.NewDocumentVersionApprovalDecision(decision),
|
|
}, nil
|
|
}
|
|
|
|
// ExportDocumentVersionPDF is the resolver for the exportDocumentVersionPDF field.
|
|
func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input types.ExportDocumentVersionPDFInput) (*types.ExportDocumentVersionPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionExportPDF); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
watermarkEmail := input.WatermarkEmail
|
|
if input.WithWatermark && watermarkEmail == nil {
|
|
identity := authn.IdentityFromContext(ctx)
|
|
watermarkEmail = &identity.EmailAddress
|
|
}
|
|
|
|
options := probo.ExportPDFOptions{
|
|
WithSignatures: input.WithSignatures,
|
|
WithWatermark: input.WithWatermark,
|
|
WatermarkEmail: watermarkEmail,
|
|
}
|
|
|
|
pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot export document version PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportDocumentVersionPDFPayload{
|
|
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
|
}, nil
|
|
}
|
|
|
|
// ExportEmployeeDocumentVersionPDF is the resolver for the exportEmployeeDocumentVersionPDF field.
|
|
func (r *mutationResolver) ExportEmployeeDocumentVersionPDF(ctx context.Context, input types.ExportEmployeeDocumentVersionPDFInput) (*types.ExportEmployeeDocumentVersionPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.DocumentVersionID, probo.ActionEmployeeDocumentVersionExportPDF); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
|
|
|
documentVersion, err := prb.Documents.GetVersion(ctx, input.DocumentVersionID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get document version", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(
|
|
&identity.ID,
|
|
coredata.EmployeeFilterModeSignature,
|
|
coredata.EmployeeFilterModeApproval,
|
|
)
|
|
|
|
_, err = prb.Documents.GetWithFilter(ctx, documentVersion.DocumentID, documentFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get employee document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
options := probo.ExportPDFOptions{
|
|
WithSignatures: false,
|
|
WithWatermark: true,
|
|
WatermarkEmail: &identity.EmailAddress,
|
|
}
|
|
|
|
pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot export employee document PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportEmployeeDocumentVersionPDFPayload{
|
|
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
|
}, nil
|
|
}
|
|
|
|
// ExportProcessingActivitiesPDF is the resolver for the exportProcessingActivitiesPDF field.
|
|
func (r *mutationResolver) ExportProcessingActivitiesPDF(ctx context.Context, input types.ExportProcessingActivitiesPDFInput) (*types.ExportProcessingActivitiesPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityExport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
var snapshotIDPtr *gid.GID
|
|
if input.Filter != nil {
|
|
snapshotIDPtr = input.Filter.SnapshotID
|
|
}
|
|
processingActivityFilter := coredata.NewProcessingActivityFilter(&snapshotIDPtr)
|
|
|
|
pdf, err := prb.ProcessingActivities.ExportPDF(ctx, input.OrganizationID, processingActivityFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot export processing activities PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportProcessingActivitiesPDFPayload{
|
|
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
|
}, nil
|
|
}
|
|
|
|
// ExportDataProtectionImpactAssessmentsPDF is the resolver for the exportDataProtectionImpactAssessmentsPDF field.
|
|
func (r *mutationResolver) ExportDataProtectionImpactAssessmentsPDF(ctx context.Context, input types.ExportDataProtectionImpactAssessmentsPDFInput) (*types.ExportDataProtectionImpactAssessmentsPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentExport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
var snapshotIDPtr *gid.GID
|
|
if input.Filter != nil {
|
|
snapshotIDPtr = input.Filter.SnapshotID
|
|
}
|
|
dpiaFilter := coredata.NewDataProtectionImpactAssessmentFilter(&snapshotIDPtr)
|
|
|
|
pdf, err := prb.DataProtectionImpactAssessments.ExportPDF(ctx, input.OrganizationID, dpiaFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot export data protection impact assessments PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportDataProtectionImpactAssessmentsPDFPayload{
|
|
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
|
}, nil
|
|
}
|
|
|
|
// ExportTransferImpactAssessmentsPDF is the resolver for the exportTransferImpactAssessmentsPDF field.
|
|
func (r *mutationResolver) ExportTransferImpactAssessmentsPDF(ctx context.Context, input types.ExportTransferImpactAssessmentsPDFInput) (*types.ExportTransferImpactAssessmentsPDFPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentExport); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
var snapshotIDPtr *gid.GID
|
|
if input.Filter != nil {
|
|
snapshotIDPtr = input.Filter.SnapshotID
|
|
}
|
|
tiaFilter := coredata.NewTransferImpactAssessmentFilter(&snapshotIDPtr)
|
|
|
|
pdf, err := prb.TransferImpactAssessments.ExportPDF(ctx, input.OrganizationID, tiaFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot export transfer impact assessments PDF", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ExportTransferImpactAssessmentsPDFPayload{
|
|
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field.
|
|
func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.VendorID, probo.ActionVendorRiskAssessmentCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
|
|
|
vendorRiskAssessment, err := prb.Vendors.CreateRiskAssessment(
|
|
ctx,
|
|
probo.CreateVendorRiskAssessmentRequest{
|
|
VendorID: input.VendorID,
|
|
ExpiresAt: input.ExpiresAt,
|
|
DataSensitivity: input.DataSensitivity,
|
|
BusinessImpact: input.BusinessImpact,
|
|
Notes: input.Notes,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create vendor risk assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateVendorRiskAssessmentPayload{
|
|
VendorRiskAssessmentEdge: types.NewVendorRiskAssessmentEdge(vendorRiskAssessment, coredata.VendorRiskAssessmentOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// AssessVendor is the resolver for the assessVendor field.
|
|
func (r *mutationResolver) AssessVendor(ctx context.Context, input types.AssessVendorInput) (*types.AssessVendorPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionVendorAssess); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Assess(
|
|
ctx,
|
|
probo.AssessVendorRequest{
|
|
ID: input.ID,
|
|
WebsiteURL: input.WebsiteURL,
|
|
},
|
|
)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot assess vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.AssessVendorPayload{
|
|
Vendor: types.NewVendor(vendor),
|
|
}, nil
|
|
}
|
|
|
|
// CreateAsset is the resolver for the createAsset field.
|
|
func (r *mutationResolver) CreateAsset(ctx context.Context, input types.CreateAssetInput) (*types.CreateAssetPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAssetCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
asset, err := prb.Assets.Create(
|
|
ctx,
|
|
probo.CreateAssetRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Amount: input.Amount,
|
|
OwnerID: input.OwnerID,
|
|
AssetType: input.AssetType,
|
|
DataTypesStored: input.DataTypesStored,
|
|
VendorIDs: input.VendorIds,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create asset", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateAssetPayload{
|
|
AssetEdge: types.NewAssetEdge(asset, coredata.AssetOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAsset is the resolver for the updateAsset field.
|
|
func (r *mutationResolver) UpdateAsset(ctx context.Context, input types.UpdateAssetInput) (*types.UpdateAssetPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionAssetUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
asset, err := prb.Assets.Update(
|
|
ctx,
|
|
probo.UpdateAssetRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Amount: input.Amount,
|
|
OwnerID: input.OwnerID,
|
|
AssetType: input.AssetType,
|
|
DataTypesStored: input.DataTypesStored,
|
|
VendorIDs: input.VendorIds,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update asset", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateAssetPayload{
|
|
Asset: types.NewAsset(asset),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAsset is the resolver for the deleteAsset field.
|
|
func (r *mutationResolver) DeleteAsset(ctx context.Context, input types.DeleteAssetInput) (*types.DeleteAssetPayload, error) {
|
|
if err := r.authorize(ctx, input.AssetID, probo.ActionAssetDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AssetID.TenantID())
|
|
|
|
err := prb.Assets.Delete(ctx, input.AssetID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete asset", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteAssetPayload{
|
|
DeletedAssetID: input.AssetID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateDatum is the resolver for the createDatum field.
|
|
func (r *mutationResolver) CreateDatum(ctx context.Context, input types.CreateDatumInput) (*types.CreateDatumPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionDatumCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
data, err := prb.Data.Create(
|
|
ctx,
|
|
probo.CreateDatumRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
DataClassification: input.DataClassification,
|
|
OwnerID: input.OwnerID,
|
|
VendorIDs: input.VendorIds,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create datum", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDatumPayload{
|
|
DatumEdge: types.NewDatumEdge(data, coredata.DatumOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDatum is the resolver for the updateDatum field.
|
|
func (r *mutationResolver) UpdateDatum(ctx context.Context, input types.UpdateDatumInput) (*types.UpdateDatumPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionDatumUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
datum, err := prb.Data.Update(
|
|
ctx,
|
|
probo.UpdateDatumRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
DataClassification: input.DataClassification,
|
|
OwnerID: input.OwnerID,
|
|
VendorIDs: input.VendorIds,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update datum", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateDatumPayload{
|
|
Datum: types.NewDatum(datum),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteDatum is the resolver for the deleteDatum field.
|
|
func (r *mutationResolver) DeleteDatum(ctx context.Context, input types.DeleteDatumInput) (*types.DeleteDatumPayload, error) {
|
|
if err := r.authorize(ctx, input.DatumID, probo.ActionDatumDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DatumID.TenantID())
|
|
|
|
if err := prb.Data.Delete(ctx, input.DatumID); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete datum", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteDatumPayload{
|
|
DeletedDatumID: input.DatumID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateAudit is the resolver for the createAudit field.
|
|
func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAuditInput) (*types.CreateAuditPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAuditCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateAuditRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
FrameworkID: input.FrameworkID,
|
|
Name: input.Name,
|
|
ValidFrom: input.ValidFrom,
|
|
ValidUntil: input.ValidUntil,
|
|
State: input.State,
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
}
|
|
|
|
audit, err := prb.Audits.Create(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create audit", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if input.File != nil {
|
|
uploadReq := probo.UploadAuditReportRequest{
|
|
AuditID: audit.ID,
|
|
File: probo.File{
|
|
Content: input.File.File,
|
|
Filename: input.File.Filename,
|
|
Size: input.File.Size,
|
|
ContentType: input.File.ContentType,
|
|
},
|
|
}
|
|
|
|
audit, err = prb.Audits.UploadReport(ctx, uploadReq)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload audit report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
}
|
|
|
|
return &types.CreateAuditPayload{
|
|
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAudit is the resolver for the updateAudit field.
|
|
func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAuditInput) (*types.UpdateAuditPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionAuditUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateAuditRequest{
|
|
ID: input.ID,
|
|
Name: gqlutils.UnwrapOmittable(input.Name),
|
|
ValidFrom: input.ValidFrom,
|
|
ValidUntil: input.ValidUntil,
|
|
State: input.State,
|
|
TrustCenterVisibility: input.TrustCenterVisibility,
|
|
}
|
|
|
|
audit, err := prb.Audits.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update audit", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateAuditPayload{
|
|
Audit: types.NewAudit(audit),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAudit is the resolver for the deleteAudit field.
|
|
func (r *mutationResolver) DeleteAudit(ctx context.Context, input types.DeleteAuditInput) (*types.DeleteAuditPayload, error) {
|
|
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
|
|
|
err := prb.Audits.Delete(ctx, input.AuditID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete audit", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteAuditPayload{
|
|
DeletedAuditID: &input.AuditID,
|
|
}, nil
|
|
}
|
|
|
|
// UploadAuditReport is the resolver for the uploadAuditReport field.
|
|
func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.UploadAuditReportInput) (*types.UploadAuditReportPayload, error) {
|
|
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditReportUpload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
|
|
|
req := probo.UploadAuditReportRequest{
|
|
AuditID: input.AuditID,
|
|
File: probo.File{
|
|
Content: input.File.File,
|
|
Filename: input.File.Filename,
|
|
Size: input.File.Size,
|
|
ContentType: input.File.ContentType,
|
|
},
|
|
}
|
|
|
|
audit, err := prb.Audits.UploadReport(ctx, req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot upload audit report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UploadAuditReportPayload{
|
|
Audit: types.NewAudit(audit),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAuditReport is the resolver for the deleteAuditReport field.
|
|
func (r *mutationResolver) DeleteAuditReport(ctx context.Context, input types.DeleteAuditReportInput) (*types.DeleteAuditReportPayload, error) {
|
|
if err := r.authorize(ctx, input.AuditID, probo.ActionAuditReportDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.AuditID.TenantID())
|
|
|
|
audit, err := prb.Audits.DeleteReport(ctx, input.AuditID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete audit report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteAuditReportPayload{
|
|
Audit: types.NewAudit(audit),
|
|
}, nil
|
|
}
|
|
|
|
// CreateFinding is the resolver for the createFinding field.
|
|
func (r *mutationResolver) CreateFinding(ctx context.Context, input types.CreateFindingInput) (*types.CreateFindingPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionFindingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateFindingRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Kind: input.Kind,
|
|
Description: input.Description,
|
|
Source: input.Source,
|
|
IdentifiedOn: input.IdentifiedOn,
|
|
RootCause: input.RootCause,
|
|
CorrectiveAction: input.CorrectiveAction,
|
|
OwnerID: input.OwnerID,
|
|
DueDate: input.DueDate,
|
|
Status: &input.Status,
|
|
Priority: &input.Priority,
|
|
RiskID: input.RiskID,
|
|
EffectivenessCheck: input.EffectivenessCheck,
|
|
}
|
|
|
|
finding, err := prb.Findings.Create(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create finding", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateFindingPayload{
|
|
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateFinding is the resolver for the updateFinding field.
|
|
func (r *mutationResolver) UpdateFinding(ctx context.Context, input types.UpdateFindingInput) (*types.UpdateFindingPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionFindingUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateFindingRequest{
|
|
ID: input.ID,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
Source: gqlutils.UnwrapOmittable(input.Source),
|
|
IdentifiedOn: gqlutils.UnwrapOmittable(input.IdentifiedOn),
|
|
RootCause: gqlutils.UnwrapOmittable(input.RootCause),
|
|
CorrectiveAction: gqlutils.UnwrapOmittable(input.CorrectiveAction),
|
|
OwnerID: input.OwnerID,
|
|
DueDate: gqlutils.UnwrapOmittable(input.DueDate),
|
|
Status: input.Status,
|
|
Priority: input.Priority,
|
|
RiskID: gqlutils.UnwrapOmittable(input.RiskID),
|
|
EffectivenessCheck: gqlutils.UnwrapOmittable(input.EffectivenessCheck),
|
|
}
|
|
|
|
finding, err := prb.Findings.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update finding", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateFindingPayload{
|
|
Finding: types.NewFinding(finding),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteFinding is the resolver for the deleteFinding field.
|
|
func (r *mutationResolver) DeleteFinding(ctx context.Context, input types.DeleteFindingInput) (*types.DeleteFindingPayload, error) {
|
|
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
|
|
|
err := prb.Findings.Delete(ctx, input.FindingID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete finding", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteFindingPayload{
|
|
DeletedFindingID: &input.FindingID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateFindingAuditMapping is the resolver for the createFindingAuditMapping field.
|
|
func (r *mutationResolver) CreateFindingAuditMapping(ctx context.Context, input types.CreateFindingAuditMappingInput) (*types.CreateFindingAuditMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
|
|
|
finding, audit, err := prb.Findings.CreateAuditMapping(ctx, input.FindingID, input.AuditID, input.ReferenceID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create finding audit mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateFindingAuditMappingPayload{
|
|
FindingEdge: types.NewFindingEdge(finding, coredata.FindingOrderFieldCreatedAt),
|
|
AuditEdge: types.NewAuditEdge(audit, coredata.AuditOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteFindingAuditMapping is the resolver for the deleteFindingAuditMapping field.
|
|
func (r *mutationResolver) DeleteFindingAuditMapping(ctx context.Context, input types.DeleteFindingAuditMappingInput) (*types.DeleteFindingAuditMappingPayload, error) {
|
|
if err := r.authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.FindingID.TenantID())
|
|
|
|
finding, audit, err := prb.Findings.DeleteAuditMapping(ctx, input.FindingID, input.AuditID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete finding audit mapping", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteFindingAuditMappingPayload{
|
|
DeletedFindingID: &finding.ID,
|
|
DeletedAuditID: &audit.ID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateObligation is the resolver for the createObligation field.
|
|
func (r *mutationResolver) CreateObligation(ctx context.Context, input types.CreateObligationInput) (*types.CreateObligationPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionObligationCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateObligationRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Area: input.Area,
|
|
Source: input.Source,
|
|
Requirement: input.Requirement,
|
|
ActionsToBeImplemented: input.ActionsToBeImplemented,
|
|
Regulator: input.Regulator,
|
|
OwnerID: input.OwnerID,
|
|
LastReviewDate: input.LastReviewDate,
|
|
DueDate: input.DueDate,
|
|
Status: input.Status,
|
|
Type: input.Type,
|
|
}
|
|
|
|
obligation, err := prb.Obligations.Create(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create obligation", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateObligationPayload{
|
|
ObligationEdge: types.NewObligationEdge(obligation, coredata.ObligationOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateObligation is the resolver for the updateObligation field.
|
|
func (r *mutationResolver) UpdateObligation(ctx context.Context, input types.UpdateObligationInput) (*types.UpdateObligationPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionObligationUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateObligationRequest{
|
|
ID: input.ID,
|
|
Area: gqlutils.UnwrapOmittable(input.Area),
|
|
Source: gqlutils.UnwrapOmittable(input.Source),
|
|
Requirement: gqlutils.UnwrapOmittable(input.Requirement),
|
|
ActionsToBeImplemented: gqlutils.UnwrapOmittable(input.ActionsToBeImplemented),
|
|
Regulator: gqlutils.UnwrapOmittable(input.Regulator),
|
|
OwnerID: input.OwnerID,
|
|
LastReviewDate: gqlutils.UnwrapOmittable(input.LastReviewDate),
|
|
DueDate: gqlutils.UnwrapOmittable(input.DueDate),
|
|
Status: input.Status,
|
|
Type: input.Type,
|
|
}
|
|
|
|
obligation, err := prb.Obligations.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update obligation", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateObligationPayload{
|
|
Obligation: types.NewObligation(obligation),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteObligation is the resolver for the deleteObligation field.
|
|
func (r *mutationResolver) DeleteObligation(ctx context.Context, input types.DeleteObligationInput) (*types.DeleteObligationPayload, error) {
|
|
if err := r.authorize(ctx, input.ObligationID, probo.ActionObligationDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ObligationID.TenantID())
|
|
|
|
err := prb.Obligations.Delete(ctx, input.ObligationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete obligation", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteObligationPayload{
|
|
DeletedObligationID: input.ObligationID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRightsRequest is the resolver for the createRightsRequest field.
|
|
func (r *mutationResolver) CreateRightsRequest(ctx context.Context, input types.CreateRightsRequestInput) (*types.CreateRightsRequestPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionRightsRequestCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateRightsRequestRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
RequestType: &input.RequestType,
|
|
RequestState: &input.RequestState,
|
|
DataSubject: input.DataSubject,
|
|
Contact: input.Contact,
|
|
Details: input.Details,
|
|
Deadline: input.Deadline,
|
|
ActionTaken: input.ActionTaken,
|
|
}
|
|
|
|
rightsRequest, err := prb.RightsRequests.Create(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create rights request", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateRightsRequestPayload{
|
|
RightsRequestEdge: types.NewRightsRequestEdge(rightsRequest, coredata.RightsRequestOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateRightsRequest is the resolver for the updateRightsRequest field.
|
|
func (r *mutationResolver) UpdateRightsRequest(ctx context.Context, input types.UpdateRightsRequestInput) (*types.UpdateRightsRequestPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionRightsRequestUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateRightsRequestRequest{
|
|
ID: input.ID,
|
|
RequestType: input.RequestType,
|
|
RequestState: input.RequestState,
|
|
DataSubject: gqlutils.UnwrapOmittable(input.DataSubject),
|
|
Contact: gqlutils.UnwrapOmittable(input.Contact),
|
|
Details: gqlutils.UnwrapOmittable(input.Details),
|
|
Deadline: gqlutils.UnwrapOmittable(input.Deadline),
|
|
ActionTaken: gqlutils.UnwrapOmittable(input.ActionTaken),
|
|
}
|
|
|
|
rightsRequest, err := prb.RightsRequests.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update rights request", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateRightsRequestPayload{
|
|
RightsRequest: types.NewRightsRequest(rightsRequest),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRightsRequest is the resolver for the deleteRightsRequest field.
|
|
func (r *mutationResolver) DeleteRightsRequest(ctx context.Context, input types.DeleteRightsRequestInput) (*types.DeleteRightsRequestPayload, error) {
|
|
if err := r.authorize(ctx, input.RightsRequestID, probo.ActionRightsRequestDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.RightsRequestID.TenantID())
|
|
|
|
err := prb.RightsRequests.Delete(ctx, input.RightsRequestID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete rights request", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteRightsRequestPayload{
|
|
DeletedRightsRequestID: input.RightsRequestID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateProcessingActivity is the resolver for the createProcessingActivity field.
|
|
func (r *mutationResolver) CreateProcessingActivity(ctx context.Context, input types.CreateProcessingActivityInput) (*types.CreateProcessingActivityPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateProcessingActivityRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Purpose: input.Purpose,
|
|
DataSubjectCategory: input.DataSubjectCategory,
|
|
PersonalDataCategory: input.PersonalDataCategory,
|
|
SpecialOrCriminalData: input.SpecialOrCriminalData,
|
|
LawfulBasis: input.LawfulBasis,
|
|
Recipients: input.Recipients,
|
|
Location: input.Location,
|
|
InternationalTransfers: input.InternationalTransfers,
|
|
TransferSafeguard: input.TransferSafeguards,
|
|
RetentionPeriod: input.RetentionPeriod,
|
|
SecurityMeasures: input.SecurityMeasures,
|
|
DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded,
|
|
TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded,
|
|
LastReviewDate: input.LastReviewDate,
|
|
NextReviewDate: input.NextReviewDate,
|
|
Role: input.Role,
|
|
DataProtectionOfficerID: input.DataProtectionOfficerID,
|
|
VendorIDs: input.VendorIds,
|
|
}
|
|
|
|
activity, err := prb.ProcessingActivities.Create(ctx, &req)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create processing activity", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateProcessingActivityPayload{
|
|
ProcessingActivityEdge: types.NewProcessingActivityEdge(activity, coredata.ProcessingActivityOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateProcessingActivity is the resolver for the updateProcessingActivity field.
|
|
func (r *mutationResolver) UpdateProcessingActivity(ctx context.Context, input types.UpdateProcessingActivityInput) (*types.UpdateProcessingActivityPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionProcessingActivityUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateProcessingActivityRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Purpose: gqlutils.UnwrapOmittable(input.Purpose),
|
|
DataSubjectCategory: gqlutils.UnwrapOmittable(input.DataSubjectCategory),
|
|
PersonalDataCategory: gqlutils.UnwrapOmittable(input.PersonalDataCategory),
|
|
SpecialOrCriminalData: input.SpecialOrCriminalData,
|
|
LawfulBasis: input.LawfulBasis,
|
|
Recipients: gqlutils.UnwrapOmittable(input.Recipients),
|
|
Location: gqlutils.UnwrapOmittable(input.Location),
|
|
InternationalTransfers: input.InternationalTransfers,
|
|
TransferSafeguard: gqlutils.UnwrapOmittable(input.TransferSafeguards),
|
|
RetentionPeriod: gqlutils.UnwrapOmittable(input.RetentionPeriod),
|
|
SecurityMeasures: gqlutils.UnwrapOmittable(input.SecurityMeasures),
|
|
DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded,
|
|
TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded,
|
|
LastReviewDate: gqlutils.UnwrapOmittable(input.LastReviewDate),
|
|
NextReviewDate: gqlutils.UnwrapOmittable(input.NextReviewDate),
|
|
Role: input.Role,
|
|
DataProtectionOfficerID: gqlutils.UnwrapOmittable(input.DataProtectionOfficerID),
|
|
VendorIDs: &input.VendorIds,
|
|
}
|
|
|
|
activity, err := prb.ProcessingActivities.Update(ctx, &req)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot update processing activity", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateProcessingActivityPayload{
|
|
ProcessingActivity: types.NewProcessingActivity(activity),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteProcessingActivity is the resolver for the deleteProcessingActivity field.
|
|
func (r *mutationResolver) DeleteProcessingActivity(ctx context.Context, input types.DeleteProcessingActivityInput) (*types.DeleteProcessingActivityPayload, error) {
|
|
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionProcessingActivityDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
|
|
|
err := prb.ProcessingActivities.Delete(ctx, input.ProcessingActivityID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete processing activity", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteProcessingActivityPayload{
|
|
DeletedProcessingActivityID: input.ProcessingActivityID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateDataProtectionImpactAssessment is the resolver for the createDataProtectionImpactAssessment field.
|
|
func (r *mutationResolver) CreateDataProtectionImpactAssessment(ctx context.Context, input types.CreateDataProtectionImpactAssessmentInput) (*types.CreateDataProtectionImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionDataProtectionImpactAssessmentCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
|
|
|
req := probo.CreateDataProtectionImpactAssessmentRequest{
|
|
ProcessingActivityID: input.ProcessingActivityID,
|
|
Description: input.Description,
|
|
NecessityAndProportionality: input.NecessityAndProportionality,
|
|
PotentialRisk: input.PotentialRisk,
|
|
Mitigations: input.Mitigations,
|
|
ResidualRisk: input.ResidualRisk,
|
|
}
|
|
|
|
dpia, err := prb.DataProtectionImpactAssessments.Create(ctx, &req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create data protection impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDataProtectionImpactAssessmentPayload{
|
|
DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDataProtectionImpactAssessment is the resolver for the updateDataProtectionImpactAssessment field.
|
|
func (r *mutationResolver) UpdateDataProtectionImpactAssessment(ctx context.Context, input types.UpdateDataProtectionImpactAssessmentInput) (*types.UpdateDataProtectionImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateDataProtectionImpactAssessmentRequest{
|
|
ID: input.ID,
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
NecessityAndProportionality: gqlutils.UnwrapOmittable(input.NecessityAndProportionality),
|
|
PotentialRisk: gqlutils.UnwrapOmittable(input.PotentialRisk),
|
|
Mitigations: gqlutils.UnwrapOmittable(input.Mitigations),
|
|
ResidualRisk: input.ResidualRisk,
|
|
}
|
|
|
|
dpia, err := prb.DataProtectionImpactAssessments.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update data protection impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateDataProtectionImpactAssessmentPayload{
|
|
DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteDataProtectionImpactAssessment is the resolver for the deleteDataProtectionImpactAssessment field.
|
|
func (r *mutationResolver) DeleteDataProtectionImpactAssessment(ctx context.Context, input types.DeleteDataProtectionImpactAssessmentInput) (*types.DeleteDataProtectionImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.DataProtectionImpactAssessmentID, probo.ActionDataProtectionImpactAssessmentDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.DataProtectionImpactAssessmentID.TenantID())
|
|
|
|
err := prb.DataProtectionImpactAssessments.Delete(ctx, input.DataProtectionImpactAssessmentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete data protection impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteDataProtectionImpactAssessmentPayload{
|
|
DeletedDataProtectionImpactAssessmentID: input.DataProtectionImpactAssessmentID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateTransferImpactAssessment is the resolver for the createTransferImpactAssessment field.
|
|
func (r *mutationResolver) CreateTransferImpactAssessment(ctx context.Context, input types.CreateTransferImpactAssessmentInput) (*types.CreateTransferImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.ProcessingActivityID, probo.ActionTransferImpactAssessmentCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID())
|
|
|
|
req := probo.CreateTransferImpactAssessmentRequest{
|
|
ProcessingActivityID: input.ProcessingActivityID,
|
|
DataSubjects: input.DataSubjects,
|
|
LegalMechanism: input.LegalMechanism,
|
|
Transfer: input.Transfer,
|
|
LocalLawRisk: input.LocalLawRisk,
|
|
SupplementaryMeasures: input.SupplementaryMeasures,
|
|
}
|
|
|
|
tia, err := prb.TransferImpactAssessments.Create(ctx, &req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create transfer impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateTransferImpactAssessmentPayload{
|
|
TransferImpactAssessment: types.NewTransferImpactAssessment(tia),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTransferImpactAssessment is the resolver for the updateTransferImpactAssessment field.
|
|
func (r *mutationResolver) UpdateTransferImpactAssessment(ctx context.Context, input types.UpdateTransferImpactAssessmentInput) (*types.UpdateTransferImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.ID, probo.ActionTransferImpactAssessmentUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ID.TenantID())
|
|
|
|
req := probo.UpdateTransferImpactAssessmentRequest{
|
|
ID: input.ID,
|
|
DataSubjects: gqlutils.UnwrapOmittable(input.DataSubjects),
|
|
LegalMechanism: gqlutils.UnwrapOmittable(input.LegalMechanism),
|
|
Transfer: gqlutils.UnwrapOmittable(input.Transfer),
|
|
LocalLawRisk: gqlutils.UnwrapOmittable(input.LocalLawRisk),
|
|
SupplementaryMeasures: gqlutils.UnwrapOmittable(input.SupplementaryMeasures),
|
|
}
|
|
|
|
tia, err := prb.TransferImpactAssessments.Update(ctx, &req)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot update transfer impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateTransferImpactAssessmentPayload{
|
|
TransferImpactAssessment: types.NewTransferImpactAssessment(tia),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTransferImpactAssessment is the resolver for the deleteTransferImpactAssessment field.
|
|
func (r *mutationResolver) DeleteTransferImpactAssessment(ctx context.Context, input types.DeleteTransferImpactAssessmentInput) (*types.DeleteTransferImpactAssessmentPayload, error) {
|
|
if err := r.authorize(ctx, input.TransferImpactAssessmentID, probo.ActionTransferImpactAssessmentDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.TransferImpactAssessmentID.TenantID())
|
|
|
|
err := prb.TransferImpactAssessments.Delete(ctx, input.TransferImpactAssessmentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete transfer impact assessment", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteTransferImpactAssessmentPayload{
|
|
DeletedTransferImpactAssessmentID: input.TransferImpactAssessmentID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateSnapshot is the resolver for the createSnapshot field.
|
|
func (r *mutationResolver) CreateSnapshot(ctx context.Context, input types.CreateSnapshotInput) (*types.CreateSnapshotPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionSnapshotCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
snapshot, err := prb.Snapshots.Create(
|
|
ctx,
|
|
&probo.CreateSnapshotRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Type: input.Type,
|
|
},
|
|
)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create snapshot", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateSnapshotPayload{
|
|
SnapshotEdge: types.NewSnapshotEdge(snapshot, coredata.SnapshotOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteSnapshot is the resolver for the deleteSnapshot field.
|
|
func (r *mutationResolver) DeleteSnapshot(ctx context.Context, input types.DeleteSnapshotInput) (*types.DeleteSnapshotPayload, error) {
|
|
if err := r.authorize(ctx, input.SnapshotID, probo.ActionSnapshotDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.SnapshotID.TenantID())
|
|
|
|
err := prb.Snapshots.Delete(ctx, input.SnapshotID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete snapshot", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteSnapshotPayload{
|
|
DeletedSnapshotID: input.SnapshotID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateCustomDomain is the resolver for the createCustomDomain field.
|
|
func (r *mutationResolver) CreateCustomDomain(ctx context.Context, input types.CreateCustomDomainInput) (*types.CreateCustomDomainPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionCustomDomainCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
domain, err := prb.CustomDomains.CreateCustomDomain(
|
|
ctx,
|
|
probo.CreateCustomDomainRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Domain: input.Domain,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot create custom domain", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateCustomDomainPayload{
|
|
CustomDomain: types.NewCustomDomain(domain, r.customDomainCname),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteCustomDomain is the resolver for the deleteCustomDomain field.
|
|
func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.DeleteCustomDomainInput) (*types.DeleteCustomDomainPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionCustomDomainDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
// TODO Drop this wierd logic
|
|
// Get the current custom domain ID before deleting
|
|
domain, err := prb.CustomDomains.GetOrganizationCustomDomain(ctx, input.OrganizationID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get custom domain", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if domain == nil {
|
|
return nil, fmt.Errorf("organization has no custom domain")
|
|
}
|
|
|
|
deletedDomainID := domain.ID
|
|
|
|
if err := prb.CustomDomains.DeleteCustomDomain(ctx, input.OrganizationID); err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete custom domain", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteCustomDomainPayload{
|
|
DeletedCustomDomainID: deletedDomainID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateAccessSource is the resolver for the createAccessSource field.
|
|
func (r *mutationResolver) CreateAccessSource(ctx context.Context, input types.CreateAccessSourceInput) (*types.CreateAccessSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAccessSourceCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
|
|
|
|
source, err := r.accessReview.Sources(scope).Create(ctx, accessreview.CreateAccessSourceRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
ConnectorID: input.ConnectorID,
|
|
Name: input.Name,
|
|
Category: coredata.AccessSourceCategorySaaS,
|
|
CsvData: input.CSVData,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create access source: %w", err))
|
|
}
|
|
|
|
return &types.CreateAccessSourcePayload{
|
|
AccessSourceEdge: types.NewAccessSourceEdge(source, coredata.AccessSourceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAccessSource is the resolver for the updateAccessSource field.
|
|
func (r *mutationResolver) UpdateAccessSource(ctx context.Context, input types.UpdateAccessSourceInput) (*types.UpdateAccessSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.AccessSourceID, probo.ActionAccessSourceUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessSourceID)
|
|
|
|
req := accessreview.UpdateAccessSourceRequest{
|
|
AccessSourceID: input.AccessSourceID,
|
|
}
|
|
if input.Name.IsSet() {
|
|
req.Name = input.Name.Value()
|
|
}
|
|
if input.ConnectorID.IsSet() {
|
|
req.ConnectorID = gqlutils.UnwrapOmittable(input.ConnectorID)
|
|
}
|
|
if input.CSVData.IsSet() {
|
|
req.CsvData = gqlutils.UnwrapOmittable(input.CSVData)
|
|
}
|
|
|
|
source, err := r.accessReview.Sources(scope).Update(ctx, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot update access source: %w", err))
|
|
}
|
|
|
|
return &types.UpdateAccessSourcePayload{
|
|
AccessSource: types.NewAccessSource(source),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAccessSource is the resolver for the deleteAccessSource field.
|
|
func (r *mutationResolver) DeleteAccessSource(ctx context.Context, input types.DeleteAccessSourceInput) (*types.DeleteAccessSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.AccessSourceID, probo.ActionAccessSourceDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessSourceID)
|
|
|
|
if err := r.accessReview.Sources(scope).Delete(ctx, input.AccessSourceID); err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot delete access source: %w", err))
|
|
}
|
|
|
|
return &types.DeleteAccessSourcePayload{
|
|
DeletedAccessSourceID: input.AccessSourceID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateAccessReviewCampaign is the resolver for the createAccessReviewCampaign field.
|
|
func (r *mutationResolver) CreateAccessReviewCampaign(ctx context.Context, input types.CreateAccessReviewCampaignInput) (*types.CreateAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionAccessReviewCampaignCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
|
|
|
|
var description string
|
|
if input.Description != nil {
|
|
description = *input.Description
|
|
}
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Create(ctx, accessreview.CreateAccessReviewCampaignRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: description,
|
|
FrameworkControls: input.FrameworkControls,
|
|
AccessSourceIDs: input.AccessSourceIds,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.CreateAccessReviewCampaignPayload{
|
|
AccessReviewCampaignEdge: types.NewAccessReviewCampaignEdge(campaign, coredata.AccessReviewCampaignOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAccessReviewCampaign is the resolver for the updateAccessReviewCampaign field.
|
|
func (r *mutationResolver) UpdateAccessReviewCampaign(ctx context.Context, input types.UpdateAccessReviewCampaignInput) (*types.UpdateAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
req := accessreview.UpdateAccessReviewCampaignRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
}
|
|
if input.Name.IsSet() {
|
|
req.Name = input.Name.Value()
|
|
}
|
|
if input.Description.IsSet() {
|
|
req.Description = input.Description.Value()
|
|
}
|
|
if input.FrameworkControls.IsSet() {
|
|
controls := input.FrameworkControls.Value()
|
|
req.FrameworkControls = &controls
|
|
}
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Update(ctx, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot update access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.UpdateAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAccessReviewCampaign is the resolver for the deleteAccessReviewCampaign field.
|
|
func (r *mutationResolver) DeleteAccessReviewCampaign(ctx context.Context, input types.DeleteAccessReviewCampaignInput) (*types.DeleteAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
if err := r.accessReview.Campaigns(scope).Delete(ctx, input.AccessReviewCampaignID); err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot delete access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.DeleteAccessReviewCampaignPayload{
|
|
DeletedAccessReviewCampaignID: input.AccessReviewCampaignID,
|
|
}, nil
|
|
}
|
|
|
|
// StartAccessReviewCampaign is the resolver for the startAccessReviewCampaign field.
|
|
func (r *mutationResolver) StartAccessReviewCampaign(ctx context.Context, input types.StartAccessReviewCampaignInput) (*types.StartAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignStart); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Start(ctx, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot start access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.StartAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// CloseAccessReviewCampaign is the resolver for the closeAccessReviewCampaign field.
|
|
func (r *mutationResolver) CloseAccessReviewCampaign(ctx context.Context, input types.CloseAccessReviewCampaignInput) (*types.CloseAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignClose); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Close(ctx, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot close access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.CloseAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// CancelAccessReviewCampaign is the resolver for the cancelAccessReviewCampaign field.
|
|
func (r *mutationResolver) CancelAccessReviewCampaign(ctx context.Context, input types.CancelAccessReviewCampaignInput) (*types.CancelAccessReviewCampaignPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignCancel); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).Cancel(ctx, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot cancel access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.CancelAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// AddAccessReviewCampaignScopeSource is the resolver for the addAccessReviewCampaignScopeSource field.
|
|
func (r *mutationResolver) AddAccessReviewCampaignScopeSource(ctx context.Context, input types.AddAccessReviewCampaignScopeSourceInput) (*types.AddAccessReviewCampaignScopeSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignAddScopeSource); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).AddScopeSource(ctx, accessreview.AddCampaignScopeSourceRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
AccessSourceID: input.AccessSourceID,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot add scope source to access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.AddAccessReviewCampaignScopeSourcePayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// RemoveAccessReviewCampaignScopeSource is the resolver for the removeAccessReviewCampaignScopeSource field.
|
|
func (r *mutationResolver) RemoveAccessReviewCampaignScopeSource(ctx context.Context, input types.RemoveAccessReviewCampaignScopeSourceInput) (*types.RemoveAccessReviewCampaignScopeSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.AccessReviewCampaignID, probo.ActionAccessReviewCampaignRemoveScopeSource); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessReviewCampaignID)
|
|
|
|
campaign, err := r.accessReview.Campaigns(scope).RemoveScopeSource(ctx, accessreview.RemoveCampaignScopeSourceRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
AccessSourceID: input.AccessSourceID,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot remove scope source from access review campaign: %w", err))
|
|
}
|
|
|
|
return &types.RemoveAccessReviewCampaignScopeSourcePayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// RecordAccessEntryDecision is the resolver for the recordAccessEntryDecision field.
|
|
func (r *mutationResolver) RecordAccessEntryDecision(ctx context.Context, input types.RecordAccessEntryDecisionInput) (*types.RecordAccessEntryDecisionPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessEntryID, probo.ActionAccessEntryDecide); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessEntryID)
|
|
|
|
// Resolve the profile ID from the session's identity.
|
|
// The profile may not exist for every identity, in which
|
|
// case decided_by will be left nil.
|
|
identity := authn.IdentityFromContext(ctx)
|
|
if identity == nil {
|
|
return nil, fmt.Errorf("no identity in context")
|
|
}
|
|
|
|
req := accessreview.RecordAccessEntryDecisionRequest{
|
|
EntryID: input.AccessEntryID,
|
|
Decision: input.Decision,
|
|
DecisionNote: input.DecisionNote,
|
|
}
|
|
|
|
organizationID, err := r.accessReview.ResolveEntryOrganizationID(ctx, input.AccessEntryID)
|
|
if err == nil {
|
|
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, organizationID)
|
|
if err == nil {
|
|
req.DecidedByID = &profile.ID
|
|
}
|
|
}
|
|
|
|
entry, err := r.accessReview.Entries(scope).RecordDecision(ctx, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot record access entry decision: %w", err))
|
|
}
|
|
|
|
return &types.RecordAccessEntryDecisionPayload{
|
|
AccessEntry: types.NewAccessEntry(entry),
|
|
}, nil
|
|
}
|
|
|
|
// RecordAccessEntryDecisions is the resolver for the recordAccessEntryDecisions field.
|
|
func (r *mutationResolver) RecordAccessEntryDecisions(ctx context.Context, input types.RecordAccessEntryDecisionsInput) (*types.RecordAccessEntryDecisionsPayload, error) {
|
|
if len(input.Decisions) == 0 {
|
|
return &types.RecordAccessEntryDecisionsPayload{
|
|
AccessEntries: []*types.AccessEntry{},
|
|
}, nil
|
|
}
|
|
|
|
const maxBatchSize = 100
|
|
if len(input.Decisions) > maxBatchSize {
|
|
return nil, fmt.Errorf("cannot record decisions: batch size %d exceeds maximum of %d", len(input.Decisions), maxBatchSize)
|
|
}
|
|
|
|
// Authorize each entry individually to prevent cross-org bypass.
|
|
for _, d := range input.Decisions {
|
|
if err := r.authorize(ctx, d.AccessEntryID, probo.ActionAccessEntryDecide); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
if identity == nil {
|
|
return nil, fmt.Errorf("no identity in context")
|
|
}
|
|
|
|
tenantID := input.Decisions[0].AccessEntryID.TenantID()
|
|
scope := coredata.NewScope(tenantID)
|
|
|
|
// Cache profile lookups per organization so we resolve the correct
|
|
// decidedByID for each entry even when a batch spans multiple orgs.
|
|
profileCache := make(map[gid.GID]*gid.GID)
|
|
|
|
decisions := make([]accessreview.RecordAccessEntryDecisionRequest, len(input.Decisions))
|
|
for i, d := range input.Decisions {
|
|
var decidedByID *gid.GID
|
|
organizationID, err := r.accessReview.ResolveEntryOrganizationID(ctx, d.AccessEntryID)
|
|
if err == nil {
|
|
if cached, ok := profileCache[organizationID]; ok {
|
|
decidedByID = cached
|
|
} else {
|
|
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, organizationID)
|
|
if err == nil {
|
|
decidedByID = &profile.ID
|
|
}
|
|
profileCache[organizationID] = decidedByID
|
|
}
|
|
}
|
|
|
|
decisions[i] = accessreview.RecordAccessEntryDecisionRequest{
|
|
EntryID: d.AccessEntryID,
|
|
Decision: d.Decision,
|
|
DecisionNote: d.DecisionNote,
|
|
DecidedByID: decidedByID,
|
|
}
|
|
}
|
|
|
|
entries, err := r.accessReview.Entries(scope).RecordDecisions(ctx, decisions)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot record access entry decisions: %w", err))
|
|
}
|
|
|
|
accessEntries := make([]*types.AccessEntry, len(entries))
|
|
for i, e := range entries {
|
|
accessEntries[i] = types.NewAccessEntry(e)
|
|
}
|
|
|
|
return &types.RecordAccessEntryDecisionsPayload{
|
|
AccessEntries: accessEntries,
|
|
}, nil
|
|
}
|
|
|
|
// FlagAccessEntry is the resolver for the flagAccessEntry field.
|
|
func (r *mutationResolver) FlagAccessEntry(ctx context.Context, input types.FlagAccessEntryInput) (*types.FlagAccessEntryPayload, error) {
|
|
if err := r.authorize(ctx, input.AccessEntryID, probo.ActionAccessEntryFlag); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessEntryID)
|
|
|
|
entry, err := r.accessReview.Entries(scope).FlagEntry(ctx, accessreview.FlagAccessEntryRequest{
|
|
EntryID: input.AccessEntryID,
|
|
Flags: input.Flags,
|
|
FlagReasons: input.FlagReasons,
|
|
})
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot flag access entry: %w", err))
|
|
}
|
|
|
|
return &types.FlagAccessEntryPayload{
|
|
AccessEntry: types.NewAccessEntry(entry),
|
|
}, nil
|
|
}
|
|
|
|
// CreateAPIKeyConnector is the resolver for the createAPIKeyConnector field.
|
|
func (r *mutationResolver) CreateAPIKeyConnector(ctx context.Context, input types.CreateAPIKeyConnectorInput) (*types.CreateAPIKeyConnectorPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionConnectorCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
req := probo.CreateConnectorRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Provider: input.Provider,
|
|
Protocol: coredata.ConnectorProtocolAPIKey,
|
|
Connection: &connector.APIKeyConnection{APIKey: input.APIKey},
|
|
}
|
|
|
|
if input.TallyOrganizationID != nil {
|
|
req.TallySettings = &coredata.TallyConnectorSettings{
|
|
OrganizationID: *input.TallyOrganizationID,
|
|
}
|
|
}
|
|
if input.SentryOrganizationSlug != nil {
|
|
req.SentrySettings = &coredata.SentryConnectorSettings{
|
|
OrganizationSlug: *input.SentryOrganizationSlug,
|
|
}
|
|
}
|
|
if input.SupabaseOrganizationSlug != nil {
|
|
req.SupabaseSettings = &coredata.SupabaseConnectorSettings{
|
|
OrganizationSlug: *input.SupabaseOrganizationSlug,
|
|
}
|
|
}
|
|
if input.GithubOrganization != nil {
|
|
req.GitHubSettings = &coredata.GitHubConnectorSettings{
|
|
Organization: *input.GithubOrganization,
|
|
}
|
|
}
|
|
if input.OnePasswordScimBridgeURL != nil {
|
|
req.OnePasswordSettings = &coredata.OnePasswordConnectorSettings{
|
|
SCIMBridgeURL: *input.OnePasswordScimBridgeURL,
|
|
}
|
|
}
|
|
cnnctr, err := prb.Connectors.Create(ctx, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
panic(fmt.Errorf("cannot create API key connector: %w", err))
|
|
}
|
|
|
|
return &types.CreateAPIKeyConnectorPayload{
|
|
Connector: types.NewConnector(cnnctr),
|
|
}, nil
|
|
}
|
|
|
|
// CreateClientCredentialsConnector is the resolver for the createClientCredentialsConnector field.
|
|
func (r *mutationResolver) CreateClientCredentialsConnector(ctx context.Context, input types.CreateClientCredentialsConnectorInput) (*types.CreateClientCredentialsConnectorPayload, error) {
|
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionConnectorCreate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
|
|
|
oauth2Conn := &connector.OAuth2Connection{
|
|
GrantType: connector.OAuth2GrantTypeClientCredentials,
|
|
ClientID: input.ClientID,
|
|
ClientSecret: input.ClientSecret,
|
|
TokenURL: input.TokenURL,
|
|
}
|
|
if input.Scope != nil {
|
|
oauth2Conn.Scope = *input.Scope
|
|
}
|
|
|
|
req := probo.CreateConnectorRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Provider: input.Provider,
|
|
Protocol: coredata.ConnectorProtocolOAuth2,
|
|
Connection: oauth2Conn,
|
|
}
|
|
|
|
if input.OnePasswordAccountID != nil && input.OnePasswordRegion != nil {
|
|
req.OnePasswordUsersAPISettings = &coredata.OnePasswordUsersAPISettings{
|
|
AccountID: *input.OnePasswordAccountID,
|
|
Region: *input.OnePasswordRegion,
|
|
}
|
|
}
|
|
|
|
cnnctr, err := prb.Connectors.Create(ctx, req)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
panic(fmt.Errorf("cannot create client credentials connector: %w", err))
|
|
}
|
|
|
|
return &types.CreateClientCredentialsConnectorPayload{
|
|
Connector: types.NewConnector(cnnctr),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteConnector is the resolver for the deleteConnector field.
|
|
func (r *mutationResolver) DeleteConnector(ctx context.Context, input types.DeleteConnectorInput) (*types.DeleteConnectorPayload, error) {
|
|
if err := r.authorize(ctx, input.ConnectorID, probo.ActionConnectorDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.ConnectorID.TenantID())
|
|
|
|
if err := prb.Connectors.Delete(ctx, input.ConnectorID); err != nil {
|
|
panic(fmt.Errorf("cannot delete connector: %w", err))
|
|
}
|
|
|
|
return &types.DeleteConnectorPayload{
|
|
DeletedConnectorID: input.ConnectorID,
|
|
}, nil
|
|
}
|
|
|
|
// ConfigureAccessSource is the resolver for the configureAccessSource field.
|
|
func (r *mutationResolver) ConfigureAccessSource(ctx context.Context, input types.ConfigureAccessSourceInput) (*types.ConfigureAccessSourcePayload, error) {
|
|
if err := r.authorize(ctx, input.AccessSourceID, probo.ActionAccessSourceUpdate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(input.AccessSourceID)
|
|
|
|
source, err := r.accessReview.Sources(scope).ConfigureAccessSource(
|
|
ctx,
|
|
accessreview.ConfigureAccessSourceRequest{
|
|
AccessSourceID: input.AccessSourceID,
|
|
OrganizationSlug: input.OrganizationSlug,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
panic(fmt.Errorf("cannot configure access source: %w", err))
|
|
}
|
|
|
|
return &types.ConfigureAccessSourcePayload{
|
|
AccessSource: types.NewAccessSource(source),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteSlackConnection is the resolver for the deleteSlackConnection field.
|
|
func (r *mutationResolver) DeleteSlackConnection(ctx context.Context, input types.DeleteSlackConnectionInput) (*types.DeleteSlackConnectionPayload, error) {
|
|
if err := r.authorize(ctx, input.SlackConnectionID, probo.ActionConnectorDelete); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, input.SlackConnectionID.TenantID())
|
|
|
|
err := prb.Connectors.Delete(ctx, input.SlackConnectionID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot delete slack connection", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteSlackConnectionPayload{
|
|
DeletedSlackConnectionID: input.SlackConnectionID,
|
|
}, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *obligationResolver) Organization(ctx context.Context, obj *types.Obligation) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get obligation organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *obligationResolver) Owner(ctx context.Context, obj *types.Obligation) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get obligation owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *obligationResolver) Permission(ctx context.Context, obj *types.Obligation, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *types.ObligationConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionObligationList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
obligationFilter := coredata.NewObligationFilter(nil)
|
|
if obj.Filter != nil {
|
|
obligationFilter = coredata.NewObligationFilter(&obj.Filter.SnapshotID)
|
|
}
|
|
|
|
count, err := prb.Obligations.CountForOrganizationID(ctx, obj.ParentID, obligationFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count obligations", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *riskResolver:
|
|
obligationFilter := coredata.NewObligationFilter(nil)
|
|
if obj.Filter != nil {
|
|
obligationFilter = coredata.NewObligationFilter(&obj.Filter.SnapshotID)
|
|
}
|
|
|
|
count, err := prb.Obligations.CountForRiskID(ctx, obj.ParentID, obligationFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count risk obligations", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// LogoURL is the resolver for the logoUrl field.
|
|
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetLogoUrl); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
logoURL, err := prb.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate logo url", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return logoURL, nil
|
|
}
|
|
|
|
// HorizontalLogoURL is the resolver for the horizontalLogoUrl field.
|
|
func (r *organizationResolver) HorizontalLogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetHorizontalLogoUrl); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
horizontalLogoURL, err := prb.Organizations.GenerateHorizontalLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate horizontal logo url", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return horizontalLogoURL, nil
|
|
}
|
|
|
|
// Context is the resolver for the context field.
|
|
func (r *organizationResolver) Context(ctx context.Context, obj *types.Organization) (*types.OrganizationContext, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationContextGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
orgContext, err := prb.Organizations.GetContext(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load organization context", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganizationContext(orgContext), nil
|
|
}
|
|
|
|
// Profiles is the resolver for the profiles field.
|
|
func (r *organizationResolver) Profiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProfileOrderBy, filter *types.ProfileFilter) (*types.ProfileConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
|
return &types.ProfileConnection{
|
|
Resolver: r,
|
|
ParentID: obj.ID,
|
|
}, nil
|
|
}
|
|
|
|
filters := coredata.NewMembershipProfileFilter(nil).WithMembership()
|
|
if filter != nil {
|
|
filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded).WithMembership()
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{
|
|
Field: coredata.MembershipProfileOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy.Field = coredata.MembershipProfileOrderField(orderBy.Field)
|
|
pageOrderBy.Direction = page.OrderDirection(orderBy.Direction)
|
|
}
|
|
|
|
cursor := cursor.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := r.iam.OrganizationService.ListProfiles(ctx, obj.ID, cursor, filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list profiles", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfileConnection(page, r, obj.ID, filters), nil
|
|
}
|
|
|
|
// SlackConnections is the resolver for the slackConnections field.
|
|
func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SlackConnectionConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionSlackConnectionList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
slackProvider := coredata.ConnectorProviderSlack
|
|
filter := coredata.NewConnectorProviderFilter(&slackProvider)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ConnectorOrderField]{
|
|
Field: coredata.ConnectorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Connectors.ListForOrganizationID(ctx, obj.ID, cursor, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization slack connections", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewSlackConnectionConnection(page), nil
|
|
}
|
|
|
|
// SlackOAuth2Scopes is the resolver for the slackOAuth2Scopes field.
|
|
func (r *organizationResolver) SlackOAuth2Scopes(ctx context.Context, obj *types.Organization) ([]string, error) {
|
|
return slack.OAuth2Scopes, nil
|
|
}
|
|
|
|
// Connectors is the resolver for the connectors field.
|
|
func (r *organizationResolver) Connectors(ctx context.Context, obj *types.Organization, filter *types.ConnectorFilter) ([]*types.Connector, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionConnectorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
connectors, err := prb.Connectors.ListAllForOrganizationID(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization connectors: %w", err))
|
|
}
|
|
|
|
if filter != nil && len(filter.Providers) > 0 {
|
|
allowed := make(map[coredata.ConnectorProvider]struct{}, len(filter.Providers))
|
|
for _, provider := range filter.Providers {
|
|
allowed[provider] = struct{}{}
|
|
}
|
|
|
|
filtered := make(coredata.Connectors, 0, len(connectors))
|
|
for _, cnnctr := range connectors {
|
|
if _, ok := allowed[cnnctr.Provider]; ok {
|
|
filtered = append(filtered, cnnctr)
|
|
}
|
|
}
|
|
connectors = filtered
|
|
}
|
|
|
|
return types.NewConnectors(connectors), nil
|
|
}
|
|
|
|
// ConnectorProviderInfos is the resolver for the connectorProviderInfos field.
|
|
func (r *organizationResolver) ConnectorProviderInfos(ctx context.Context, obj *types.Organization) ([]*types.ConnectorProviderInfo, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionConnectorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var infos []*types.ConnectorProviderInfo
|
|
for _, provider := range coredata.ConnectorProviders() {
|
|
_, oauthErr := r.connectorRegistry.Get(string(provider))
|
|
scopes := drivers.ProviderOAuth2Scopes(provider)
|
|
if scopes == nil {
|
|
scopes = []string{}
|
|
}
|
|
info := &types.ConnectorProviderInfo{
|
|
Provider: provider,
|
|
DisplayName: providerDisplayName(provider),
|
|
OauthConfigured: oauthErr == nil,
|
|
APIKeySupported: providerSupportsAPIKey(provider),
|
|
ClientCredentialsSupported: providerSupportsClientCredentials(provider),
|
|
Oauth2Scopes: scopes,
|
|
ExtraSettings: providerExtraSettings(provider),
|
|
}
|
|
infos = append(infos, info)
|
|
}
|
|
return infos, nil
|
|
}
|
|
|
|
// Frameworks is the resolver for the frameworks field.
|
|
func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) (*types.FrameworkConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFrameworkList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.FrameworkOrderField]{
|
|
Field: coredata.FrameworkOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.FrameworkOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Frameworks.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization frameworks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFrameworkConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *organizationResolver) Controls(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForOrganizationID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// Vendors is the resolver for the vendors field.
|
|
func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy, filter *types.VendorFilter) (*types.VendorConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
|
Field: coredata.VendorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var vendorFilter = coredata.NewVendorFilter(nil, nil)
|
|
if filter != nil {
|
|
vendorFilter = coredata.NewVendorFilter(&filter.SnapshotID, nil)
|
|
}
|
|
|
|
page, err := prb.Vendors.ListForOrganizationID(ctx, obj.ID, cursor, vendorFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization vendors", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Documents is the resolver for the documents field.
|
|
func (r *organizationResolver) Documents(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldTitle,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var documentFilter = coredata.NewDocumentFilter(nil)
|
|
if filter != nil {
|
|
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
|
WithDocumentTypes(filter.DocumentTypes).
|
|
WithClassifications(filter.Classifications).
|
|
WithStatus(filter.Status)
|
|
}
|
|
|
|
page, err := prb.Documents.ListByOrganizationID(ctx, obj.ID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentConnection(page, r, obj.ID, documentFilter), nil
|
|
}
|
|
|
|
// Meetings is the resolver for the meetings field.
|
|
func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeetingOrderBy) (*types.MeetingConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeetingList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MeetingOrderField]{
|
|
Field: coredata.MeetingOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MeetingOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Meetings.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization meetings", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeetingConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// StatementsOfApplicability is the resolver for the statementsOfApplicability field.
|
|
func (r *organizationResolver) StatementsOfApplicability(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StatementOfApplicabilityOrderBy, filter *types.StatementOfApplicabilityFilter) (*types.StatementOfApplicabilityConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionStatementOfApplicabilityList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
|
Field: coredata.StatementOfApplicabilityOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var statementOfApplicabilityFilter = coredata.NewStatementOfApplicabilityFilter(nil)
|
|
if filter != nil {
|
|
statementOfApplicabilityFilter = coredata.NewStatementOfApplicabilityFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.StatementsOfApplicability.ListForOrganizationID(ctx, obj.ID, cursor, statementOfApplicabilityFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization statements_of_applicability", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewStatementOfApplicabilityConnection(page, r, obj.ID, statementOfApplicabilityFilter), nil
|
|
}
|
|
|
|
// MeasureCategories is the resolver for the measureCategories field.
|
|
func (r *organizationResolver) MeasureCategories(ctx context.Context, obj *types.Organization) ([]string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
categories, err := prb.Measures.ListDistinctCategoriesForOrganizationID(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure categories", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return categories, nil
|
|
}
|
|
|
|
// Measures is the resolver for the measures field.
|
|
func (r *organizationResolver) Measures(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: coredata.MeasureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var measureFilter = coredata.NewMeasureFilter(nil, nil, nil)
|
|
if filter != nil {
|
|
measureFilter = coredata.NewMeasureFilter(filter.Query, filter.State, filter.Category)
|
|
}
|
|
|
|
page, err := prb.Measures.ListForOrganizationID(ctx, obj.ID, cursor, measureFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization measures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeasureConnection(page, r, obj.ID, measureFilter), nil
|
|
}
|
|
|
|
// Risks is the resolver for the risks field.
|
|
func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionRiskList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.RiskOrderField]{
|
|
Field: coredata.RiskOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.RiskOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var riskFilter = coredata.NewRiskFilter(nil, nil)
|
|
if filter != nil {
|
|
riskFilter = coredata.NewRiskFilter(filter.Query, &filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Risks.ListForOrganizationID(ctx, obj.ID, cursor, riskFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization risks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRiskConnection(page, r, obj.ID, riskFilter), nil
|
|
}
|
|
|
|
// Tasks is the resolver for the tasks field.
|
|
func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTaskList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TaskOrderField]{
|
|
Field: coredata.TaskOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TaskOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Tasks.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization tasks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTaskConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Assets is the resolver for the assets field.
|
|
func (r *organizationResolver) Assets(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AssetOrderBy, filter *types.AssetFilter) (*types.AssetConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAssetList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AssetOrderField]{
|
|
Field: coredata.AssetOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AssetOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
assetFilter := coredata.NewAssetFilter(nil)
|
|
if filter != nil {
|
|
assetFilter = coredata.NewAssetFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Assets.ListForOrganizationID(ctx, obj.ID, cursor, assetFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization assets", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAssetConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Assets is the resolver for the assets field.
|
|
func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy, filter *types.DatumFilter) (*types.DatumConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDatumList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DatumOrderField]{
|
|
Field: coredata.DatumOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DatumOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
datumFilter := coredata.NewDatumFilter(nil)
|
|
if filter != nil {
|
|
datumFilter = coredata.NewDatumFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Data.ListForOrganizationID(ctx, obj.ID, cursor, datumFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization data", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDataConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Audits is the resolver for the audits field.
|
|
func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAuditList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
|
|
Field: coredata.AuditOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Audits.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization audits", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAuditConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Findings is the resolver for the findings field.
|
|
func (r *organizationResolver) Findings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FindingOrder, filter *types.FindingFilter) (*types.FindingConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFindingList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.FindingOrderField]{
|
|
Field: coredata.FindingOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.FindingOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var (
|
|
kind *coredata.FindingKind
|
|
status *coredata.FindingStatus
|
|
priority *coredata.FindingPriority
|
|
ownerID *gid.GID
|
|
)
|
|
if filter != nil {
|
|
kind = filter.Kind
|
|
status = filter.Status
|
|
priority = filter.Priority
|
|
ownerID = filter.OwnerID
|
|
}
|
|
|
|
findingFilter := coredata.NewFindingFilter(nil, kind, status, priority, ownerID)
|
|
if filter != nil {
|
|
findingFilter = coredata.NewFindingFilter(&filter.SnapshotID, kind, status, priority, ownerID)
|
|
}
|
|
|
|
page, err := prb.Findings.ListForOrganizationID(ctx, obj.ID, cursor, findingFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization findings", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFindingConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Obligations is the resolver for the obligations field.
|
|
func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionObligationList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: coredata.ObligationOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
obligationFilter := coredata.NewObligationFilter(nil)
|
|
if filter != nil {
|
|
obligationFilter = coredata.NewObligationFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Obligations.ListForOrganizationID(ctx, obj.ID, cursor, obligationFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization obligations", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// RightsRequests is the resolver for the rightsRequests field.
|
|
func (r *organizationResolver) RightsRequests(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RightsRequestOrderBy) (*types.RightsRequestConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionRightsRequestList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.RightsRequestOrderField]{
|
|
Field: coredata.RightsRequestOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.RightsRequestOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.RightsRequests.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization rights requests", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRightsRequestConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// ProcessingActivities is the resolver for the processingActivities field.
|
|
func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityOrderBy, filter *types.ProcessingActivityFilter) (*types.ProcessingActivityConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ProcessingActivityOrderField]{
|
|
Field: coredata.ProcessingActivityOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ProcessingActivityOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
processingActivityFilter := coredata.NewProcessingActivityFilter(nil)
|
|
if filter != nil {
|
|
processingActivityFilter = coredata.NewProcessingActivityFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.ProcessingActivities.ListForOrganizationID(ctx, obj.ID, cursor, processingActivityFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization processing activities", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProcessingActivityConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// DataProtectionImpactAssessments is the resolver for the dataProtectionImpactAssessments field.
|
|
func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DataProtectionImpactAssessmentOrderBy, filter *types.DataProtectionImpactAssessmentFilter) (*types.DataProtectionImpactAssessmentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{
|
|
Field: coredata.DataProtectionImpactAssessmentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
dpiaFilter := coredata.NewDataProtectionImpactAssessmentFilter(nil)
|
|
if filter != nil {
|
|
dpiaFilter = coredata.NewDataProtectionImpactAssessmentFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.DataProtectionImpactAssessments.ListForOrganizationID(ctx, obj.ID, cursor, dpiaFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization data protection impact assessments", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDataProtectionImpactAssessmentConnection(page, r, obj.ID, dpiaFilter), nil
|
|
}
|
|
|
|
// TransferImpactAssessments is the resolver for the transferImpactAssessments field.
|
|
func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TransferImpactAssessmentOrderBy, filter *types.TransferImpactAssessmentFilter) (*types.TransferImpactAssessmentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TransferImpactAssessmentOrderField]{
|
|
Field: coredata.TransferImpactAssessmentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TransferImpactAssessmentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
tiaFilter := coredata.NewTransferImpactAssessmentFilter(nil)
|
|
if filter != nil {
|
|
tiaFilter = coredata.NewTransferImpactAssessmentFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.TransferImpactAssessments.ListForOrganizationID(ctx, obj.ID, cursor, tiaFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization transfer impact assessments", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTransferImpactAssessmentConnection(page, r, obj.ID, tiaFilter), nil
|
|
}
|
|
|
|
// Snapshots is the resolver for the snapshots field.
|
|
func (r *organizationResolver) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionSnapshotList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.SnapshotOrderField]{
|
|
Field: coredata.SnapshotOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.SnapshotOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Snapshots.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization snapshots", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewSnapshotConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// TrustCenterFiles is the resolver for the trustCenterFiles field.
|
|
func (r *organizationResolver) TrustCenterFiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterFileOrderField]) (*types.TrustCenterFileConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterFileList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TrustCenterFileOrderField]{
|
|
Field: coredata.TrustCenterFileOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TrustCenterFileOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
pageResult, err := prb.TrustCenterFiles.ListForOrganizationID(ctx, obj.ID, cursor, &coredata.TrustCenterFileFilter{})
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization trust center files", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTrustCenterFileConnection(pageResult, obj.ID), nil
|
|
}
|
|
|
|
// TrustCenter is the resolver for the trustCenter field.
|
|
func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
trustCenter, err := prb.TrustCenters.GetByOrganizationID(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
var file *coredata.File
|
|
if trustCenter.NonDisclosureAgreementFileID != nil {
|
|
file, err = prb.Files.Get(ctx, *trustCenter.NonDisclosureAgreementFileID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get NDA file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
}
|
|
|
|
return types.NewTrustCenter(trustCenter, file), nil
|
|
}
|
|
|
|
// CustomDomain is the resolver for the customDomain field.
|
|
func (r *organizationResolver) CustomDomain(ctx context.Context, obj *types.Organization) (*types.CustomDomain, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionCustomDomainGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
domain, err := prb.CustomDomains.GetOrganizationCustomDomain(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get custom domain", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if domain == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return types.NewCustomDomain(domain, r.customDomainCname), nil
|
|
}
|
|
|
|
// WebhookSubscriptions is the resolver for the webhookSubscriptions field.
|
|
func (r *organizationResolver) WebhookSubscriptions(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.WebhookSubscriptionOrderBy) (*types.WebhookSubscriptionConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.WebhookSubscriptionOrderField]{
|
|
Field: coredata.WebhookSubscriptionOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.WebhookSubscriptionOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.WebhookSubscriptions.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization webhook subscriptions", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewWebhookSubscriptionConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// AuditLogEntries is the resolver for the auditLogEntries field.
|
|
func (r *organizationResolver) AuditLogEntries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditLogEntryOrderBy, filter *types.AuditLogEntryFilter) (*types.AuditLogEntryConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionAuditLogEntryList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AuditLogEntryOrderField]{
|
|
Field: coredata.AuditLogEntryOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AuditLogEntryOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
coredataFilter := coredata.NewAuditLogEntryFilter()
|
|
if filter != nil {
|
|
if filter.Action != nil {
|
|
coredataFilter.WithAction(*filter.Action)
|
|
}
|
|
if filter.ActorID != nil {
|
|
coredataFilter.WithActorID(*filter.ActorID)
|
|
}
|
|
if filter.ResourceType != nil {
|
|
coredataFilter.WithResourceType(*filter.ResourceType)
|
|
}
|
|
if filter.ResourceID != nil {
|
|
coredataFilter.WithResourceID(*filter.ResourceID)
|
|
}
|
|
}
|
|
|
|
p, err := r.iam.OrganizationService.ListAuditLogEntries(ctx, obj.ID, cursor, coredataFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list audit log entries", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAuditLogEntryConnection(p, r, obj.ID, coredataFilter), nil
|
|
}
|
|
|
|
// AccessSources is the resolver for the accessSources field.
|
|
func (r *organizationResolver) AccessSources(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessSourceOrder) (*types.AccessSourceConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessSourceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessSourceOrderField]{
|
|
Field: coredata.AccessSourceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessSourceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.Sources(scope).ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access sources: %w", err))
|
|
}
|
|
|
|
return types.NewAccessSourceConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// AccessReviewCampaigns is the resolver for the accessReviewCampaigns field.
|
|
func (r *organizationResolver) AccessReviewCampaigns(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessReviewCampaignOrder) (*types.AccessReviewCampaignConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAccessReviewCampaignList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
scope := coredata.NewScopeFromObjectID(obj.ID)
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessReviewCampaignOrderField]{
|
|
Field: coredata.AccessReviewCampaignOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessReviewCampaignOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.Campaigns(scope).ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list access review campaigns: %w", err))
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *organizationResolver) Permission(ctx context.Context, obj *types.Organization, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *processingActivityResolver) Organization(ctx context.Context, obj *types.ProcessingActivity) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// DataProtectionOfficer is the resolver for the dataProtectionOfficer field.
|
|
func (r *processingActivityResolver) DataProtectionOfficer(ctx context.Context, obj *types.ProcessingActivity) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.DataProtectionOfficer == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
dpo, err := loaders.Profile.Load(ctx, obj.DataProtectionOfficer.ID)
|
|
if err != nil {
|
|
if errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get data protection officer", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(dpo), nil
|
|
}
|
|
|
|
// Vendors is the resolver for the vendors field.
|
|
func (r *processingActivityResolver) Vendors(ctx context.Context, obj *types.ProcessingActivity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
|
|
Field: coredata.VendorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Vendors.ListForProcessingActivityID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list processing activity vendors", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// DataProtectionImpactAssessment is the resolver for the dataProtectionImpactAssessment field.
|
|
func (r *processingActivityResolver) DataProtectionImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.DataProtectionImpactAssessment, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
dpia, err := prb.DataProtectionImpactAssessments.GetByProcessingActivityID(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity dpia", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDataProtectionImpactAssessment(dpia), nil
|
|
}
|
|
|
|
// TransferImpactAssessment is the resolver for the transferImpactAssessment field.
|
|
func (r *processingActivityResolver) TransferImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.TransferImpactAssessment, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
tia, err := prb.TransferImpactAssessments.GetByProcessingActivityID(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity tia", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTransferImpactAssessment(tia), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *processingActivityResolver) Permission(ctx context.Context, obj *types.ProcessingActivity, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *processingActivityConnectionResolver) TotalCount(ctx context.Context, obj *types.ProcessingActivityConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionProcessingActivityList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
processingActivityFilter := coredata.NewProcessingActivityFilter(nil)
|
|
if obj.Filter != nil {
|
|
processingActivityFilter = coredata.NewProcessingActivityFilter(&obj.Filter.SnapshotID)
|
|
}
|
|
|
|
count, err := prb.ProcessingActivities.CountForOrganizationID(ctx, obj.ParentID, processingActivityFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count organization processing activities", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *profileResolver) Permission(ctx context.Context, obj *types.Profile, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.ProfileConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, iam.ActionMembershipProfileList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.iam.OrganizationService.CountProfiles(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count profiles", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *documentVersionResolver:
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
count, err := prb.Documents.CountVersionApprovers(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count document version approvers", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver for profile connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Node is the resolver for the node field.
|
|
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
var (
|
|
loadNode func(ctx context.Context, id gid.GID) (types.Node, error)
|
|
action string
|
|
prb = r.ProboService(ctx, id.TenantID())
|
|
)
|
|
|
|
switch id.EntityType() {
|
|
case coredata.OrganizationEntityType:
|
|
action = iam.ActionOrganizationGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
organization, err := prb.Organizations.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
case coredata.VendorEntityType:
|
|
action = probo.ActionVendorGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
vendor, err := prb.Vendors.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
case coredata.FrameworkEntityType:
|
|
action = probo.ActionFrameworkGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
framework, err := prb.Frameworks.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewFramework(framework), nil
|
|
}
|
|
case coredata.MeasureEntityType:
|
|
action = probo.ActionMeasureGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
measure, err := prb.Measures.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewMeasure(measure), nil
|
|
}
|
|
case coredata.TaskEntityType:
|
|
action = probo.ActionTaskGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
task, err := prb.Tasks.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewTask(task), nil
|
|
}
|
|
case coredata.EvidenceEntityType:
|
|
action = probo.ActionEvidenceList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
evidence, err := prb.Evidences.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewEvidence(evidence), nil
|
|
}
|
|
case coredata.DocumentEntityType:
|
|
action = probo.ActionDocumentGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
document, err := prb.Documents.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewDocument(document), nil
|
|
}
|
|
case coredata.ControlEntityType:
|
|
action = probo.ActionControlList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
control, err := prb.Controls.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewControl(control), nil
|
|
}
|
|
case coredata.RiskEntityType:
|
|
action = probo.ActionRiskGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
risk, err := prb.Risks.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewRisk(risk), nil
|
|
}
|
|
case coredata.VendorComplianceReportEntityType:
|
|
action = probo.ActionVendorComplianceReportGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
vendorComplianceReport, err := prb.VendorComplianceReports.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewVendorComplianceReport(vendorComplianceReport), nil
|
|
}
|
|
case coredata.VendorContactEntityType:
|
|
action = probo.ActionVendorContactGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
vendorContact, err := prb.VendorContacts.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewVendorContact(vendorContact), nil
|
|
}
|
|
case coredata.VendorServiceEntityType:
|
|
action = probo.ActionVendorServiceGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
vendorService, err := prb.VendorServices.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewVendorService(vendorService), nil
|
|
}
|
|
case coredata.DocumentVersionEntityType:
|
|
action = probo.ActionDocumentVersionList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
documentVersion, err := prb.Documents.GetVersion(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewDocumentVersion(documentVersion), nil
|
|
}
|
|
case coredata.DocumentVersionSignatureEntityType:
|
|
action = probo.ActionDocumentVersionSignatureList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
documentVersionSignature, err := prb.Documents.GetVersionSignature(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewDocumentVersionSignature(documentVersionSignature), nil
|
|
}
|
|
case coredata.AssetEntityType:
|
|
action = probo.ActionAssetList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
asset, err := prb.Assets.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewAsset(asset), nil
|
|
}
|
|
case coredata.DatumEntityType:
|
|
action = probo.ActionDatumList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
datum, err := prb.Data.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewDatum(datum), nil
|
|
}
|
|
case coredata.AuditEntityType:
|
|
action = probo.ActionAuditList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
audit, err := prb.Audits.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewAudit(audit), nil
|
|
}
|
|
case coredata.FindingEntityType:
|
|
action = probo.ActionFindingList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
finding, err := prb.Findings.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewFinding(finding), nil
|
|
}
|
|
case coredata.ObligationEntityType:
|
|
action = probo.ActionObligationList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
obligation, err := prb.Obligations.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewObligation(obligation), nil
|
|
}
|
|
case coredata.ReportEntityType:
|
|
action = probo.ActionReportGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
report, err := prb.Reports.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewReport(report), nil
|
|
}
|
|
case coredata.ProcessingActivityEntityType:
|
|
action = probo.ActionProcessingActivityList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
processingActivity, err := prb.ProcessingActivities.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewProcessingActivity(processingActivity), nil
|
|
}
|
|
case coredata.DataProtectionImpactAssessmentEntityType:
|
|
// TODO: add action
|
|
// action = probo.ActionDataProtectionImpactAssessmentGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewDataProtectionImpactAssessment(dpia), nil
|
|
}
|
|
case coredata.TransferImpactAssessmentEntityType:
|
|
// TODO: add action
|
|
//action = probo.ActionTransferImpactAssessmentGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
tia, err := prb.TransferImpactAssessments.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewTransferImpactAssessment(tia), nil
|
|
}
|
|
case coredata.SnapshotEntityType:
|
|
action = probo.ActionSnapshotList
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
snapshot, err := prb.Snapshots.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewSnapshot(snapshot), nil
|
|
}
|
|
case coredata.TrustCenterEntityType:
|
|
action = probo.ActionTrustCenterGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
trustCenter, err := prb.TrustCenters.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var file *coredata.File
|
|
if trustCenter.NonDisclosureAgreementFileID != nil {
|
|
file, err = prb.Files.Get(ctx, *trustCenter.NonDisclosureAgreementFileID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get NDA file: %w", err)
|
|
}
|
|
}
|
|
|
|
return types.NewTrustCenter(trustCenter, file), nil
|
|
}
|
|
case coredata.TrustCenterAccessEntityType:
|
|
action = probo.ActionTrustCenterAccessGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
trustCenterAccess, err := prb.TrustCenterAccesses.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewTrustCenterAccess(trustCenterAccess), nil
|
|
}
|
|
case coredata.MeetingEntityType:
|
|
action = probo.ActionMeetingGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
meeting, err := prb.Meetings.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewMeeting(meeting), nil
|
|
}
|
|
case coredata.RightsRequestEntityType:
|
|
action = probo.ActionRightsRequestGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
rightsRequest, err := prb.RightsRequests.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewRightsRequest(rightsRequest), nil
|
|
}
|
|
case coredata.StatementOfApplicabilityEntityType:
|
|
action = probo.ActionStatementOfApplicabilityGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
statementOfApplicability, err := prb.StatementsOfApplicability.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewStatementOfApplicability(statementOfApplicability), nil
|
|
}
|
|
case coredata.WebhookSubscriptionEntityType:
|
|
action = probo.ActionWebhookSubscriptionGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
wc, err := prb.WebhookSubscriptions.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewWebhookSubscription(wc), nil
|
|
}
|
|
case coredata.AccessReviewCampaignEntityType:
|
|
action = probo.ActionAccessReviewCampaignGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
scope := coredata.NewScopeFromObjectID(id)
|
|
campaign, err := r.accessReview.Campaigns(scope).Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewAccessReviewCampaign(campaign), nil
|
|
}
|
|
case coredata.AccessSourceEntityType:
|
|
action = probo.ActionAccessSourceGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
scope := coredata.NewScopeFromObjectID(id)
|
|
source, err := r.accessReview.Sources(scope).Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewAccessSource(source), nil
|
|
}
|
|
case coredata.AccessEntryEntityType:
|
|
action = probo.ActionAccessEntryGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
scope := coredata.NewScopeFromObjectID(id)
|
|
entry, err := r.accessReview.Entries(scope).Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return types.NewAccessEntry(entry), nil
|
|
}
|
|
default:
|
|
}
|
|
|
|
if err := r.authorize(ctx, id, action); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
node, err := loadNode(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load node", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return node, nil
|
|
}
|
|
|
|
// Viewer is the resolver for the viewer field.
|
|
func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
session := authn.SessionFromContext(ctx)
|
|
apiKey := authn.APIKeyFromContext(ctx)
|
|
|
|
var viewerID gid.GID
|
|
if session != nil {
|
|
viewerID = session.ID
|
|
} else if apiKey != nil {
|
|
viewerID = apiKey.ID
|
|
} else {
|
|
viewerID = identity.ID
|
|
}
|
|
|
|
return &types.Viewer{ID: viewerID}, nil
|
|
}
|
|
|
|
// DownloadURL is the resolver for the downloadUrl field.
|
|
func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionReportDownloadUrlGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
url, err := prb.Reports.GenerateDownloadURL(ctx, obj.ID, 15*time.Minute)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate download URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return url, nil
|
|
}
|
|
|
|
// Audit is the resolver for the audit field.
|
|
func (r *reportResolver) Audit(ctx context.Context, obj *types.Report) (*types.Audit, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionAuditGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
audit, err := prb.Audits.GetByReportID(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load audit for report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAudit(audit), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *reportResolver) Permission(ctx context.Context, obj *types.Report, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *rightsRequestResolver) Organization(ctx context.Context, obj *types.RightsRequest) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
rightsRequest, err := prb.RightsRequests.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get rights request", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
organization, err := prb.Organizations.Get(ctx, rightsRequest.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *rightsRequestResolver) Permission(ctx context.Context, obj *types.RightsRequest, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *rightsRequestConnectionResolver) TotalCount(ctx context.Context, obj *types.RightsRequestConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionRightsRequestList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.RightsRequests.CountByOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count rights requests", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
default:
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver type for RightsRequestConnection")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Owner == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *riskResolver) Organization(ctx context.Context, obj *types.Risk) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Measures is the resolver for the measures field.
|
|
func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: coredata.MeasureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var measureFilter = coredata.NewMeasureFilter(nil, nil, nil)
|
|
if filter != nil {
|
|
measureFilter = coredata.NewMeasureFilter(filter.Query, filter.State, filter.Category)
|
|
}
|
|
|
|
page, err := prb.Measures.ListForRiskID(ctx, obj.ID, cursor, measureFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk measures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeasureConnection(page, r, obj.ID, measureFilter), nil
|
|
}
|
|
|
|
// Documents is the resolver for the documents field.
|
|
func (r *riskResolver) Documents(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var documentFilter = coredata.NewDocumentFilter(nil)
|
|
if filter != nil {
|
|
documentFilter = coredata.NewDocumentFilter(filter.Query).
|
|
WithDocumentTypes(filter.DocumentTypes).
|
|
WithClassifications(filter.Classifications)
|
|
}
|
|
|
|
page, err := prb.Documents.ListForRiskID(ctx, obj.ID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocumentConnection(page, r, obj.ID, documentFilter), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
var filters = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
filters = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForRiskID(ctx, obj.ID, cursor, filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, filters), nil
|
|
}
|
|
|
|
// Obligations is the resolver for the obligations field.
|
|
func (r *riskResolver) Obligations(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionObligationList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: coredata.ObligationOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var obligationFilter = coredata.NewObligationFilter(nil)
|
|
if filter != nil {
|
|
obligationFilter = coredata.NewObligationFilter(&filter.SnapshotID)
|
|
}
|
|
|
|
page, err := prb.Obligations.ListForRiskID(ctx, obj.ID, cursor, obligationFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk obligations", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewObligationConnection(page, r, obj.ID, filter), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *riskResolver) Permission(ctx context.Context, obj *types.Risk, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *riskConnectionResolver) TotalCount(ctx context.Context, obj *types.RiskConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionRiskList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *measureResolver:
|
|
count, err := prb.Risks.CountForMeasureID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count risks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *organizationResolver:
|
|
count, err := prb.Risks.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count risks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *slackConnectionResolver) Permission(ctx context.Context, obj *types.SlackConnection, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *snapshotResolver) Organization(ctx context.Context, obj *types.Snapshot) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
snapshot, err := prb.Snapshots.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get snapshot", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
organization, err := prb.Organizations.Get(ctx, snapshot.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *snapshotResolver) Controls(ctx context.Context, obj *types.Snapshot, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionControlList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ControlOrderField]{
|
|
Field: coredata.ControlOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ControlOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var controlFilter = coredata.NewControlFilter(nil)
|
|
if filter != nil {
|
|
controlFilter = coredata.NewControlFilter(filter.Query)
|
|
}
|
|
|
|
page, err := prb.Controls.ListForSnapshotID(ctx, obj.ID, cursor, controlFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list snapshot controls", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewControlConnection(page, r, obj.ID, controlFilter), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *snapshotResolver) Permission(ctx context.Context, obj *types.Snapshot, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *snapshotConnectionResolver) TotalCount(ctx context.Context, obj *types.SnapshotConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionSnapshotList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Snapshots.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count snapshots", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *statementOfApplicabilityResolver) Organization(ctx context.Context, obj *types.StatementOfApplicability) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *statementOfApplicabilityResolver) Owner(ctx context.Context, obj *types.StatementOfApplicability) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
r.logger.ErrorCtx(ctx, "cannot load owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// ApplicabilityStatements is the resolver for the applicabilityStatements field.
|
|
func (r *statementOfApplicabilityResolver) ApplicabilityStatements(ctx context.Context, obj *types.StatementOfApplicability, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ApplicabilityStatementOrderBy) (*types.ApplicabilityStatementConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionApplicabilityStatementList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ApplicabilityStatementOrderField]{
|
|
Field: coredata.ApplicabilityStatementOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionAsc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ApplicabilityStatementOrderField]{
|
|
Field: coredata.ApplicabilityStatementOrderField(orderBy.Field),
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := prb.StatementsOfApplicability.ListApplicabilityStatements(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list applicability statements", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewApplicabilityStatementConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *statementOfApplicabilityResolver) Permission(ctx context.Context, obj *types.StatementOfApplicability, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *statementOfApplicabilityConnectionResolver) TotalCount(ctx context.Context, obj *types.StatementOfApplicabilityConnection) (int, error) {
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.StatementsOfApplicability.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count statements_of_applicability", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// AssignedTo is the resolver for the assignedTo field.
|
|
func (r *taskResolver) AssignedTo(ctx context.Context, obj *types.Task) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.AssignedTo == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
assignee, err := loaders.Profile.Load(ctx, obj.AssignedTo.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get assigned to", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(assignee), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *taskResolver) Organization(ctx context.Context, obj *types.Task) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Measure is the resolver for the measure field.
|
|
func (r *taskResolver) Measure(ctx context.Context, obj *types.Task) (*types.Measure, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMeasureGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.Measure == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
measure, err := loaders.Measure.Load(ctx, obj.Measure.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get measure", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewMeasure(measure), nil
|
|
}
|
|
|
|
// Evidences is the resolver for the evidences field.
|
|
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionEvidenceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: coredata.EvidenceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
page, err := prb.Evidences.ListForTaskID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list task evidences", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewEvidenceConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *taskResolver) Permission(ctx context.Context, obj *types.Task, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *taskConnectionResolver) TotalCount(ctx context.Context, obj *types.TaskConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionTaskList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *measureResolver:
|
|
count, err := prb.Tasks.CountForMeasureID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count tasks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *organizationResolver:
|
|
count, err := prb.Tasks.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count tasks", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// ProcessingActivity is the resolver for the processingActivity field.
|
|
func (r *transferImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.TransferImpactAssessment) (*types.ProcessingActivity, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
processingActivity, err := prb.ProcessingActivities.Get(ctx, obj.ProcessingActivity.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activity", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProcessingActivity(processingActivity), nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *transferImpactAssessmentResolver) Organization(ctx context.Context, obj *types.TransferImpactAssessment) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *transferImpactAssessmentResolver) Permission(ctx context.Context, obj *types.TransferImpactAssessment, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *transferImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.TransferImpactAssessmentConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionTransferImpactAssessmentList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.TransferImpactAssessments.CountForOrganizationID(ctx, obj.ParentID, obj.Filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count organization transfer impact assessments", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// LogoFileURL is the resolver for the logoFileUrl field.
|
|
func (r *trustCenterResolver) LogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
logoURL, err := prb.TrustCenters.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate logo url", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return logoURL, nil
|
|
}
|
|
|
|
// DarkLogoFileURL is the resolver for the darkLogoFileUrl field.
|
|
func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
logoURL, err := prb.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate logo url", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return logoURL, nil
|
|
}
|
|
|
|
// NdaFileURL is the resolver for the ndaFileUrl field.
|
|
func (r *trustCenterResolver) NdaFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
|
|
hasPermission, err := r.Resolver.Permission(ctx, obj, probo.ActionTrustCenterGetNda)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot authorize", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if !hasPermission {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
fileURL, err := prb.TrustCenters.GenerateNDAFileURL(ctx, obj.ID, 15*time.Minute)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate NDA file URL", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
trustCenter, err := prb.TrustCenters.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
organization, err := prb.Organizations.Get(ctx, trustCenter.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Accesses is the resolver for the accesses field.
|
|
func (r *trustCenterResolver) Accesses(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterAccessOrderField]) (*types.TrustCenterAccessConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterAccessList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TrustCenterAccessOrderField]{
|
|
Field: coredata.TrustCenterAccessOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TrustCenterAccessOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := prb.TrustCenterAccesses.ListForTrustCenterID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list trust center accesses", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTrustCenterAccessConnection(result), nil
|
|
}
|
|
|
|
// References is the resolver for the references field.
|
|
func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterReferenceOrderField]) (*types.TrustCenterReferenceConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterReferenceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TrustCenterReferenceOrderField]{
|
|
Field: coredata.TrustCenterReferenceOrderFieldRank,
|
|
Direction: page.OrderDirectionAsc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TrustCenterReferenceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := prb.TrustCenterReferences.ListForTrustCenterID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list trust center references", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTrustCenterReferenceConnection(result, obj.ID), nil
|
|
}
|
|
|
|
// ComplianceFrameworks is the resolver for the complianceFrameworks field.
|
|
func (r *trustCenterResolver) ComplianceFrameworks(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.ComplianceFrameworkOrderField]) (*types.ComplianceFrameworkConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionComplianceFrameworkList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
|
Field: coredata.ComplianceFrameworkOrderFieldRank,
|
|
Direction: page.OrderDirectionAsc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := prb.ComplianceFrameworks.ListWithHiddenForTrustCenterID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list compliance frameworks", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewComplianceFrameworkConnection(result), nil
|
|
}
|
|
|
|
// ExternalUrls is the resolver for the externalUrls field.
|
|
func (r *trustCenterResolver) ExternalUrls(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.ComplianceExternalURLOrderField]) (*types.ComplianceExternalURLConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionComplianceExternalURLList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ComplianceExternalURLOrderField]{
|
|
Field: coredata.ComplianceExternalURLOrderFieldRank,
|
|
Direction: page.OrderDirectionAsc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ComplianceExternalURLOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := prb.ComplianceExternalURLs.List(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list compliance external URLs", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewComplianceExternalURLConnection(result), nil
|
|
}
|
|
|
|
// MailingList is the resolver for the mailingList field.
|
|
func (r *trustCenterResolver) MailingList(ctx context.Context, obj *types.TrustCenter) (*types.MailingList, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionMailingListSubscriberList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.MailingList != nil {
|
|
return obj.MailingList, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
ml, err := prb.TrustCenters.GetMailingList(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get mailing list for trust center", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if ml == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return types.NewMailingList(ml), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *trustCenterResolver) Permission(ctx context.Context, obj *types.TrustCenter, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// NdaSignature is the resolver for the ndaSignature field.
|
|
func (r *trustCenterAccessResolver) NdaSignature(ctx context.Context, obj *types.TrustCenterAccess) (*types.ElectronicSignature, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterAccessGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
access, err := prb.TrustCenterAccesses.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot load trust center access: %w", err)
|
|
}
|
|
|
|
if access.ElectronicSignatureID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return types.NewElectronicSignature(sig), nil
|
|
}
|
|
|
|
// PendingRequestCount is the resolver for the pendingRequestCount field.
|
|
func (r *trustCenterAccessResolver) PendingRequestCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterAccessGet); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
count, err := prb.TrustCenterAccesses.CountPendingRequestDocumentAccesses(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count pending request document accesses", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// ActiveCount is the resolver for the activeCount field.
|
|
func (r *trustCenterAccessResolver) ActiveCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterAccessGet); err != nil {
|
|
return 0, err
|
|
}
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
count, err := prb.TrustCenterAccesses.CountActiveDocumentAccesses(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count active document accesses", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Profile is the resolver for the profile field.
|
|
func (r *trustCenterAccessResolver) Profile(ctx context.Context, obj *types.TrustCenterAccess) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, obj.IdentityID, obj.OrganizationID)
|
|
if err != nil {
|
|
if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get profile", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(profile), nil
|
|
}
|
|
|
|
// AvailableDocumentAccesses is the resolver for the availableDocumentAccesses field.
|
|
func (r *trustCenterAccessResolver) AvailableDocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterAccessGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.TrustCenterDocumentAccessOrderField]{
|
|
Field: coredata.TrustCenterDocumentAccessOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.TrustCenterDocumentAccessOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
result, err := prb.TrustCenterAccesses.ListAvailableDocumentAccesses(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list trust center document accesses", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTrustCenterDocumentAccessConnection(result, obj, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *trustCenterAccessResolver) Permission(ctx context.Context, obj *types.TrustCenterAccess, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Document is the resolver for the document field.
|
|
func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.DocumentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.TrustCenterAccessID.TenantID())
|
|
|
|
document, err := prb.Documents.Get(ctx, *obj.DocumentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), nil
|
|
}
|
|
|
|
// Report is the resolver for the report field.
|
|
func (r *trustCenterDocumentAccessResolver) Report(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Report, error) {
|
|
if err := r.authorize(ctx, obj.TrustCenterAccessID, probo.ActionReportGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.ReportID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.TrustCenterAccessID.TenantID())
|
|
|
|
report, err := prb.Reports.Get(ctx, *obj.ReportID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewReport(report), nil
|
|
}
|
|
|
|
// TrustCenterFile is the resolver for the trustCenterFile field.
|
|
func (r *trustCenterDocumentAccessResolver) TrustCenterFile(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterFile, error) {
|
|
if err := r.authorize(ctx, obj.TrustCenterAccessID, probo.ActionTrustCenterFileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.TrustCenterFileID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.TrustCenterAccessID.TenantID())
|
|
|
|
trustCenterFile, err := prb.TrustCenterFiles.Get(ctx, *obj.TrustCenterFileID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewTrustCenterFile(trustCenterFile), nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *trustCenterDocumentAccessConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterDocumentAccessConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionTrustCenterDocumentAccessList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.TrustCenterAccesses.CountDocumentAccesses(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count trust center document accesses", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// FileURL is the resolver for the fileUrl field.
|
|
func (r *trustCenterFileResolver) FileURL(ctx context.Context, obj *types.TrustCenterFile) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterFileGetFileUrl); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
fileURL, err := prb.TrustCenterFiles.GenerateFileURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate file URL", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *trustCenterFileResolver) Organization(ctx context.Context, obj *types.TrustCenterFile) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
trustCenterFile, err := prb.TrustCenterFiles.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get trust center file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
organization, err := prb.Organizations.Get(ctx, trustCenterFile.OrganizationID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *trustCenterFileResolver) Permission(ctx context.Context, obj *types.TrustCenterFile, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *trustCenterFileConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterFileConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionTrustCenterFileList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.TrustCenterFiles.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count trust center files", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
// LogoURL is the resolver for the logoUrl field.
|
|
func (r *trustCenterReferenceResolver) LogoURL(ctx context.Context, obj *types.TrustCenterReference) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterReferenceGetLogoUrl); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
fileURL, err := prb.TrustCenterReferences.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate logo URL", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *trustCenterReferenceResolver) Permission(ctx context.Context, obj *types.TrustCenterReference, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *trustCenterReferenceConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterReferenceConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionTrustCenterReferenceList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.TrustCenterReferences.CountForTrustCenterID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count trust center references", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *vendorResolver) Organization(ctx context.Context, obj *types.Vendor) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// ComplianceReports is the resolver for the complianceReports field.
|
|
func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorComplianceReportList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorComplianceReportOrderField]{
|
|
Field: coredata.VendorComplianceReportOrderFieldReportDate,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorComplianceReportOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.VendorComplianceReports.ListForVendorID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list vendor compliance reports", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorComplianceReportConnection(page), nil
|
|
}
|
|
|
|
// BusinessAssociateAgreement is the resolver for the businessAssociateAgreement field.
|
|
func (r *vendorResolver) BusinessAssociateAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorBusinessAssociateAgreement, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorBusinessAssociateAgreementGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendorBusinessAssociateAgreement, file, err := prb.VendorBusinessAssociateAgreements.GetByVendorID(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor business associate agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorBusinessAssociateAgreement(vendorBusinessAssociateAgreement, file), nil
|
|
}
|
|
|
|
// DataPrivacyAgreement is the resolver for the dataPrivacyAgreement field.
|
|
func (r *vendorResolver) DataPrivacyAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorDataPrivacyAgreement, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorDataPrivacyAgreementGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.GetByVendorID(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor data privacy agreement", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file), nil
|
|
}
|
|
|
|
// Contacts is the resolver for the contacts field.
|
|
func (r *vendorResolver) Contacts(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) (*types.VendorContactConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorContactList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorContactOrderField]{
|
|
Field: coredata.VendorContactOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorContactOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.VendorContacts.List(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list vendor contacts", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorContactConnection(page), nil
|
|
}
|
|
|
|
// Services is the resolver for the services field.
|
|
func (r *vendorResolver) Services(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorServiceOrderBy) (*types.VendorServiceConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorServiceList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorServiceOrderField]{
|
|
Field: coredata.VendorServiceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorServiceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.VendorServices.List(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list vendor services", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorServiceConnection(page), nil
|
|
}
|
|
|
|
// RiskAssessments is the resolver for the riskAssessments field.
|
|
func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorRiskAssessmentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
|
|
Field: coredata.VendorRiskAssessmentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.Vendors.ListRiskAssessments(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list vendor risk assessments", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendorRiskAssessmentConnection(page), nil
|
|
}
|
|
|
|
// BusinessOwner is the resolver for the businessOwner field.
|
|
func (r *vendorResolver) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.BusinessOwner == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
businessOwner, err := loaders.Profile.Load(ctx, obj.BusinessOwner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get business owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(businessOwner), nil
|
|
}
|
|
|
|
// SecurityOwner is the resolver for the securityOwner field.
|
|
func (r *vendorResolver) SecurityOwner(ctx context.Context, obj *types.Vendor) (*types.Profile, error) {
|
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.SecurityOwner == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
securityOwner, err := loaders.Profile.Load(ctx, obj.SecurityOwner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get security owner", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(securityOwner), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorResolver) Permission(ctx context.Context, obj *types.Vendor, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorBusinessAssociateAgreementResolver) Vendor(ctx context.Context, obj *types.VendorBusinessAssociateAgreement) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
return nil, fmt.Errorf("cannot get vendor: %w", err)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// FileURL is the resolver for the fileUrl field.
|
|
func (r *vendorBusinessAssociateAgreementResolver) FileURL(ctx context.Context, obj *types.VendorBusinessAssociateAgreement) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFileDownloadUrl); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
fileURL, err := prb.VendorBusinessAssociateAgreements.GenerateFileURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate file URL", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorBusinessAssociateAgreementResolver) Permission(ctx context.Context, obj *types.VendorBusinessAssociateAgreement, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorComplianceReportResolver) Vendor(ctx context.Context, obj *types.VendorComplianceReport) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// File is the resolver for the file field.
|
|
func (r *vendorComplianceReportResolver) File(ctx context.Context, obj *types.VendorComplianceReport) (*types.File, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
evidence, err := prb.VendorComplianceReports.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load evidence", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if evidence.ReportFileId == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
file, err := prb.Files.Get(ctx, *evidence.ReportFileId)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load evidence file", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewFile(file), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorComplianceReportResolver) Permission(ctx context.Context, obj *types.VendorComplianceReport, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *vendorConnectionResolver) TotalCount(ctx context.Context, obj *types.VendorConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionVendorList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.Vendors.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count vendors", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *assetResolver:
|
|
count, err := prb.Vendors.CountForAssetID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count vendors", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
case *datumResolver:
|
|
count, err := prb.Vendors.CountForDatumID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count vendors", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver")
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorContactResolver) Vendor(ctx context.Context, obj *types.VendorContact) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
// Get the vendor contact to access the VendorID
|
|
vendorContact, err := prb.VendorContacts.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor contact", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
vendor, err := prb.Vendors.Get(ctx, vendorContact.VendorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorContactResolver) Permission(ctx context.Context, obj *types.VendorContact, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorDataPrivacyAgreementResolver) Vendor(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// FileURL is the resolver for the fileUrl field.
|
|
func (r *vendorDataPrivacyAgreementResolver) FileURL(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionFileDownloadUrl); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
fileURL, err := prb.VendorDataPrivacyAgreements.GenerateFileURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot generate file URL", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorDataPrivacyAgreementResolver) Permission(ctx context.Context, obj *types.VendorDataPrivacyAgreement, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
vendor, err := prb.Vendors.GetByRiskAssessmentID(ctx, obj.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorRiskAssessmentResolver) Permission(ctx context.Context, obj *types.VendorRiskAssessment, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorServiceResolver) Vendor(ctx context.Context, obj *types.VendorService) (*types.Vendor, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionVendorGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
vendor, err := loaders.Vendor.Load(ctx, obj.Vendor.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get vendor", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *vendorServiceResolver) Permission(ctx context.Context, obj *types.VendorService, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// SignableDocuments is the resolver for the signableDocuments field.
|
|
func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
|
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, organizationID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
|
|
|
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization signable documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
|
for i, doc := range documentsPage.Data {
|
|
employeeDocuments[i] = &types.EmployeeDocument{
|
|
ID: doc.ID,
|
|
Title: doc.Title,
|
|
DocumentType: doc.DocumentType,
|
|
CreatedAt: doc.CreatedAt,
|
|
UpdatedAt: doc.UpdatedAt,
|
|
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
|
}
|
|
}
|
|
|
|
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
|
|
|
return types.NewEmployeeDocumentConnection(page), nil
|
|
}
|
|
|
|
// SignableDocument is the resolver for the signableDocument field.
|
|
func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
|
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, id.TenantID())
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeSignature)
|
|
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get signable document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.EmployeeDocument{
|
|
ID: document.ID,
|
|
Title: document.Title,
|
|
DocumentType: document.DocumentType,
|
|
CreatedAt: document.CreatedAt,
|
|
UpdatedAt: document.UpdatedAt,
|
|
FilterMode: types.EmployeeDocumentFilterModeSignature,
|
|
}, nil
|
|
}
|
|
|
|
// ApprovableDocuments is the resolver for the approvableDocuments field.
|
|
func (r *viewerResolver) ApprovableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.EmployeeDocumentConnection, error) {
|
|
if err := r.authorize(ctx, organizationID, probo.ActionEmployeeDocumentList); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, organizationID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: coredata.DocumentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
|
|
|
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization approvable documents", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
employeeDocuments := make([]*types.EmployeeDocument, len(documentsPage.Data))
|
|
for i, doc := range documentsPage.Data {
|
|
employeeDocuments[i] = &types.EmployeeDocument{
|
|
ID: doc.ID,
|
|
Title: doc.Title,
|
|
DocumentType: doc.DocumentType,
|
|
CreatedAt: doc.CreatedAt,
|
|
UpdatedAt: doc.UpdatedAt,
|
|
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
|
}
|
|
}
|
|
|
|
page := page.NewPage(employeeDocuments, documentsPage.Cursor)
|
|
|
|
return types.NewEmployeeDocumentConnection(page), nil
|
|
}
|
|
|
|
// ApprovableDocument is the resolver for the approvableDocument field.
|
|
func (r *viewerResolver) ApprovableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.EmployeeDocument, error) {
|
|
if err := r.authorize(ctx, id, probo.ActionEmployeeDocumentGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, id.TenantID())
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
documentFilter := coredata.NewDocumentFilter(nil).WithEmployeeIdentityID(&identity.ID, coredata.EmployeeFilterModeApproval)
|
|
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get approvable document", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.EmployeeDocument{
|
|
ID: document.ID,
|
|
Title: document.Title,
|
|
DocumentType: document.DocumentType,
|
|
CreatedAt: document.CreatedAt,
|
|
UpdatedAt: document.UpdatedAt,
|
|
FilterMode: types.EmployeeDocumentFilterModeApproval,
|
|
}, nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *webhookEventConnectionResolver) TotalCount(ctx context.Context, obj *types.WebhookEventConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionWebhookSubscriptionGet); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
count, err := prb.WebhookSubscriptions.CountEventsForSubscriptionID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count webhook events", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *webhookSubscriptionResolver) Organization(ctx context.Context, obj *types.WebhookSubscription) (*types.Organization, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// SigningSecret is the resolver for the signingSecret field.
|
|
func (r *webhookSubscriptionResolver) SigningSecret(ctx context.Context, obj *types.WebhookSubscription) (string, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionUpdate); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
signingSecret, err := prb.WebhookSubscriptions.GetSigningSecret(ctx, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get signing secret", log.Error(err))
|
|
return "", gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return signingSecret, nil
|
|
}
|
|
|
|
// Events is the resolver for the events field.
|
|
func (r *webhookSubscriptionResolver) Events(ctx context.Context, obj *types.WebhookSubscription, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.WebhookEventOrderBy) (*types.WebhookEventConnection, error) {
|
|
if err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.WebhookEventOrderField]{
|
|
Field: coredata.WebhookEventOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.WebhookEventOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := prb.WebhookSubscriptions.ListEventsForSubscriptionID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list webhook events", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewWebhookEventConnection(page, r, obj.ID), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *webhookSubscriptionResolver) Permission(ctx context.Context, obj *types.WebhookSubscription, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *webhookSubscriptionConnectionResolver) TotalCount(ctx context.Context, obj *types.WebhookSubscriptionConnection) (int, error) {
|
|
if err := r.authorize(ctx, obj.ParentID, probo.ActionWebhookSubscriptionList); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := prb.WebhookSubscriptions.CountForOrganizationID(ctx, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count webhook subscriptions", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver for webhook subscription connection", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// AccessEntry returns schema.AccessEntryResolver implementation.
|
|
func (r *Resolver) AccessEntry() schema.AccessEntryResolver { return &accessEntryResolver{r} }
|
|
|
|
// AccessEntryConnection returns schema.AccessEntryConnectionResolver implementation.
|
|
func (r *Resolver) AccessEntryConnection() schema.AccessEntryConnectionResolver {
|
|
return &accessEntryConnectionResolver{r}
|
|
}
|
|
|
|
// AccessReview returns schema.AccessReviewResolver implementation.
|
|
func (r *Resolver) AccessReview() schema.AccessReviewResolver { return &accessReviewResolver{r} }
|
|
|
|
// AccessReviewCampaign returns schema.AccessReviewCampaignResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaign() schema.AccessReviewCampaignResolver {
|
|
return &accessReviewCampaignResolver{r}
|
|
}
|
|
|
|
// AccessReviewCampaignConnection returns schema.AccessReviewCampaignConnectionResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaignConnection() schema.AccessReviewCampaignConnectionResolver {
|
|
return &accessReviewCampaignConnectionResolver{r}
|
|
}
|
|
|
|
// AccessReviewCampaignScopeSource returns schema.AccessReviewCampaignScopeSourceResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaignScopeSource() schema.AccessReviewCampaignScopeSourceResolver {
|
|
return &accessReviewCampaignScopeSourceResolver{r}
|
|
}
|
|
|
|
// AccessSource returns schema.AccessSourceResolver implementation.
|
|
func (r *Resolver) AccessSource() schema.AccessSourceResolver { return &accessSourceResolver{r} }
|
|
|
|
// AccessSourceConnection returns schema.AccessSourceConnectionResolver implementation.
|
|
func (r *Resolver) AccessSourceConnection() schema.AccessSourceConnectionResolver {
|
|
return &accessSourceConnectionResolver{r}
|
|
}
|
|
|
|
// ApplicabilityStatement returns schema.ApplicabilityStatementResolver implementation.
|
|
func (r *Resolver) ApplicabilityStatement() schema.ApplicabilityStatementResolver {
|
|
return &applicabilityStatementResolver{r}
|
|
}
|
|
|
|
// ApplicabilityStatementConnection returns schema.ApplicabilityStatementConnectionResolver implementation.
|
|
func (r *Resolver) ApplicabilityStatementConnection() schema.ApplicabilityStatementConnectionResolver {
|
|
return &applicabilityStatementConnectionResolver{r}
|
|
}
|
|
|
|
// Asset returns schema.AssetResolver implementation.
|
|
func (r *Resolver) Asset() schema.AssetResolver { return &assetResolver{r} }
|
|
|
|
// AssetConnection returns schema.AssetConnectionResolver implementation.
|
|
func (r *Resolver) AssetConnection() schema.AssetConnectionResolver {
|
|
return &assetConnectionResolver{r}
|
|
}
|
|
|
|
// Audit returns schema.AuditResolver implementation.
|
|
func (r *Resolver) Audit() schema.AuditResolver { return &auditResolver{r} }
|
|
|
|
// AuditConnection returns schema.AuditConnectionResolver implementation.
|
|
func (r *Resolver) AuditConnection() schema.AuditConnectionResolver {
|
|
return &auditConnectionResolver{r}
|
|
}
|
|
|
|
// AuditLogEntry returns schema.AuditLogEntryResolver implementation.
|
|
func (r *Resolver) AuditLogEntry() schema.AuditLogEntryResolver { return &auditLogEntryResolver{r} }
|
|
|
|
// AuditLogEntryConnection returns schema.AuditLogEntryConnectionResolver implementation.
|
|
func (r *Resolver) AuditLogEntryConnection() schema.AuditLogEntryConnectionResolver {
|
|
return &auditLogEntryConnectionResolver{r}
|
|
}
|
|
|
|
// ComplianceExternalURL returns schema.ComplianceExternalURLResolver implementation.
|
|
func (r *Resolver) ComplianceExternalURL() schema.ComplianceExternalURLResolver {
|
|
return &complianceExternalURLResolver{r}
|
|
}
|
|
|
|
// ComplianceFramework returns schema.ComplianceFrameworkResolver implementation.
|
|
func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
|
|
return &complianceFrameworkResolver{r}
|
|
}
|
|
|
|
// Connector returns schema.ConnectorResolver implementation.
|
|
func (r *Resolver) Connector() schema.ConnectorResolver { return &connectorResolver{r} }
|
|
|
|
// Control returns schema.ControlResolver implementation.
|
|
func (r *Resolver) Control() schema.ControlResolver { return &controlResolver{r} }
|
|
|
|
// ControlConnection returns schema.ControlConnectionResolver implementation.
|
|
func (r *Resolver) ControlConnection() schema.ControlConnectionResolver {
|
|
return &controlConnectionResolver{r}
|
|
}
|
|
|
|
// CustomDomain returns schema.CustomDomainResolver implementation.
|
|
func (r *Resolver) CustomDomain() schema.CustomDomainResolver { return &customDomainResolver{r} }
|
|
|
|
// DataProtectionImpactAssessment returns schema.DataProtectionImpactAssessmentResolver implementation.
|
|
func (r *Resolver) DataProtectionImpactAssessment() schema.DataProtectionImpactAssessmentResolver {
|
|
return &dataProtectionImpactAssessmentResolver{r}
|
|
}
|
|
|
|
// DataProtectionImpactAssessmentConnection returns schema.DataProtectionImpactAssessmentConnectionResolver implementation.
|
|
func (r *Resolver) DataProtectionImpactAssessmentConnection() schema.DataProtectionImpactAssessmentConnectionResolver {
|
|
return &dataProtectionImpactAssessmentConnectionResolver{r}
|
|
}
|
|
|
|
// Datum returns schema.DatumResolver implementation.
|
|
func (r *Resolver) Datum() schema.DatumResolver { return &datumResolver{r} }
|
|
|
|
// DatumConnection returns schema.DatumConnectionResolver implementation.
|
|
func (r *Resolver) DatumConnection() schema.DatumConnectionResolver {
|
|
return &datumConnectionResolver{r}
|
|
}
|
|
|
|
// Document returns schema.DocumentResolver implementation.
|
|
func (r *Resolver) Document() schema.DocumentResolver { return &documentResolver{r} }
|
|
|
|
// DocumentConnection returns schema.DocumentConnectionResolver implementation.
|
|
func (r *Resolver) DocumentConnection() schema.DocumentConnectionResolver {
|
|
return &documentConnectionResolver{r}
|
|
}
|
|
|
|
// DocumentVersion returns schema.DocumentVersionResolver implementation.
|
|
func (r *Resolver) DocumentVersion() schema.DocumentVersionResolver {
|
|
return &documentVersionResolver{r}
|
|
}
|
|
|
|
// DocumentVersionApprovalDecision returns schema.DocumentVersionApprovalDecisionResolver implementation.
|
|
func (r *Resolver) DocumentVersionApprovalDecision() schema.DocumentVersionApprovalDecisionResolver {
|
|
return &documentVersionApprovalDecisionResolver{r}
|
|
}
|
|
|
|
// DocumentVersionApprovalDecisionConnection returns schema.DocumentVersionApprovalDecisionConnectionResolver implementation.
|
|
func (r *Resolver) DocumentVersionApprovalDecisionConnection() schema.DocumentVersionApprovalDecisionConnectionResolver {
|
|
return &documentVersionApprovalDecisionConnectionResolver{r}
|
|
}
|
|
|
|
// DocumentVersionApprovalQuorum returns schema.DocumentVersionApprovalQuorumResolver implementation.
|
|
func (r *Resolver) DocumentVersionApprovalQuorum() schema.DocumentVersionApprovalQuorumResolver {
|
|
return &documentVersionApprovalQuorumResolver{r}
|
|
}
|
|
|
|
// DocumentVersionApprovalQuorumConnection returns schema.DocumentVersionApprovalQuorumConnectionResolver implementation.
|
|
func (r *Resolver) DocumentVersionApprovalQuorumConnection() schema.DocumentVersionApprovalQuorumConnectionResolver {
|
|
return &documentVersionApprovalQuorumConnectionResolver{r}
|
|
}
|
|
|
|
// DocumentVersionConnection returns schema.DocumentVersionConnectionResolver implementation.
|
|
func (r *Resolver) DocumentVersionConnection() schema.DocumentVersionConnectionResolver {
|
|
return &documentVersionConnectionResolver{r}
|
|
}
|
|
|
|
// DocumentVersionSignature returns schema.DocumentVersionSignatureResolver implementation.
|
|
func (r *Resolver) DocumentVersionSignature() schema.DocumentVersionSignatureResolver {
|
|
return &documentVersionSignatureResolver{r}
|
|
}
|
|
|
|
// DocumentVersionSignatureConnection returns schema.DocumentVersionSignatureConnectionResolver implementation.
|
|
func (r *Resolver) DocumentVersionSignatureConnection() schema.DocumentVersionSignatureConnectionResolver {
|
|
return &documentVersionSignatureConnectionResolver{r}
|
|
}
|
|
|
|
// ElectronicSignature returns schema.ElectronicSignatureResolver implementation.
|
|
func (r *Resolver) ElectronicSignature() schema.ElectronicSignatureResolver {
|
|
return &electronicSignatureResolver{r}
|
|
}
|
|
|
|
// EmployeeDocument returns schema.EmployeeDocumentResolver implementation.
|
|
func (r *Resolver) EmployeeDocument() schema.EmployeeDocumentResolver {
|
|
return &employeeDocumentResolver{r}
|
|
}
|
|
|
|
// EmployeeDocumentVersion returns schema.EmployeeDocumentVersionResolver implementation.
|
|
func (r *Resolver) EmployeeDocumentVersion() schema.EmployeeDocumentVersionResolver {
|
|
return &employeeDocumentVersionResolver{r}
|
|
}
|
|
|
|
// Evidence returns schema.EvidenceResolver implementation.
|
|
func (r *Resolver) Evidence() schema.EvidenceResolver { return &evidenceResolver{r} }
|
|
|
|
// EvidenceConnection returns schema.EvidenceConnectionResolver implementation.
|
|
func (r *Resolver) EvidenceConnection() schema.EvidenceConnectionResolver {
|
|
return &evidenceConnectionResolver{r}
|
|
}
|
|
|
|
// File returns schema.FileResolver implementation.
|
|
func (r *Resolver) File() schema.FileResolver { return &fileResolver{r} }
|
|
|
|
// Finding returns schema.FindingResolver implementation.
|
|
func (r *Resolver) Finding() schema.FindingResolver { return &findingResolver{r} }
|
|
|
|
// FindingConnection returns schema.FindingConnectionResolver implementation.
|
|
func (r *Resolver) FindingConnection() schema.FindingConnectionResolver {
|
|
return &findingConnectionResolver{r}
|
|
}
|
|
|
|
// Framework returns schema.FrameworkResolver implementation.
|
|
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
|
|
|
// FrameworkConnection returns schema.FrameworkConnectionResolver implementation.
|
|
func (r *Resolver) FrameworkConnection() schema.FrameworkConnectionResolver {
|
|
return &frameworkConnectionResolver{r}
|
|
}
|
|
|
|
// MailingList returns schema.MailingListResolver implementation.
|
|
func (r *Resolver) MailingList() schema.MailingListResolver { return &mailingListResolver{r} }
|
|
|
|
// MailingListSubscriberConnection returns schema.MailingListSubscriberConnectionResolver implementation.
|
|
func (r *Resolver) MailingListSubscriberConnection() schema.MailingListSubscriberConnectionResolver {
|
|
return &mailingListSubscriberConnectionResolver{r}
|
|
}
|
|
|
|
// MailingListUpdateConnection returns schema.MailingListUpdateConnectionResolver implementation.
|
|
func (r *Resolver) MailingListUpdateConnection() schema.MailingListUpdateConnectionResolver {
|
|
return &mailingListUpdateConnectionResolver{r}
|
|
}
|
|
|
|
// Measure returns schema.MeasureResolver implementation.
|
|
func (r *Resolver) Measure() schema.MeasureResolver { return &measureResolver{r} }
|
|
|
|
// MeasureConnection returns schema.MeasureConnectionResolver implementation.
|
|
func (r *Resolver) MeasureConnection() schema.MeasureConnectionResolver {
|
|
return &measureConnectionResolver{r}
|
|
}
|
|
|
|
// Meeting returns schema.MeetingResolver implementation.
|
|
func (r *Resolver) Meeting() schema.MeetingResolver { return &meetingResolver{r} }
|
|
|
|
// MeetingConnection returns schema.MeetingConnectionResolver implementation.
|
|
func (r *Resolver) MeetingConnection() schema.MeetingConnectionResolver {
|
|
return &meetingConnectionResolver{r}
|
|
}
|
|
|
|
// Mutation returns schema.MutationResolver implementation.
|
|
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
|
|
|
// Obligation returns schema.ObligationResolver implementation.
|
|
func (r *Resolver) Obligation() schema.ObligationResolver { return &obligationResolver{r} }
|
|
|
|
// ObligationConnection returns schema.ObligationConnectionResolver implementation.
|
|
func (r *Resolver) ObligationConnection() schema.ObligationConnectionResolver {
|
|
return &obligationConnectionResolver{r}
|
|
}
|
|
|
|
// Organization returns schema.OrganizationResolver implementation.
|
|
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
|
|
|
|
// ProcessingActivity returns schema.ProcessingActivityResolver implementation.
|
|
func (r *Resolver) ProcessingActivity() schema.ProcessingActivityResolver {
|
|
return &processingActivityResolver{r}
|
|
}
|
|
|
|
// ProcessingActivityConnection returns schema.ProcessingActivityConnectionResolver implementation.
|
|
func (r *Resolver) ProcessingActivityConnection() schema.ProcessingActivityConnectionResolver {
|
|
return &processingActivityConnectionResolver{r}
|
|
}
|
|
|
|
// Profile returns schema.ProfileResolver implementation.
|
|
func (r *Resolver) Profile() schema.ProfileResolver { return &profileResolver{r} }
|
|
|
|
// ProfileConnection returns schema.ProfileConnectionResolver implementation.
|
|
func (r *Resolver) ProfileConnection() schema.ProfileConnectionResolver {
|
|
return &profileConnectionResolver{r}
|
|
}
|
|
|
|
// Query returns schema.QueryResolver implementation.
|
|
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
|
|
|
// Report returns schema.ReportResolver implementation.
|
|
func (r *Resolver) Report() schema.ReportResolver { return &reportResolver{r} }
|
|
|
|
// RightsRequest returns schema.RightsRequestResolver implementation.
|
|
func (r *Resolver) RightsRequest() schema.RightsRequestResolver { return &rightsRequestResolver{r} }
|
|
|
|
// RightsRequestConnection returns schema.RightsRequestConnectionResolver implementation.
|
|
func (r *Resolver) RightsRequestConnection() schema.RightsRequestConnectionResolver {
|
|
return &rightsRequestConnectionResolver{r}
|
|
}
|
|
|
|
// Risk returns schema.RiskResolver implementation.
|
|
func (r *Resolver) Risk() schema.RiskResolver { return &riskResolver{r} }
|
|
|
|
// RiskConnection returns schema.RiskConnectionResolver implementation.
|
|
func (r *Resolver) RiskConnection() schema.RiskConnectionResolver { return &riskConnectionResolver{r} }
|
|
|
|
// SlackConnection returns schema.SlackConnectionResolver implementation.
|
|
func (r *Resolver) SlackConnection() schema.SlackConnectionResolver {
|
|
return &slackConnectionResolver{r}
|
|
}
|
|
|
|
// Snapshot returns schema.SnapshotResolver implementation.
|
|
func (r *Resolver) Snapshot() schema.SnapshotResolver { return &snapshotResolver{r} }
|
|
|
|
// SnapshotConnection returns schema.SnapshotConnectionResolver implementation.
|
|
func (r *Resolver) SnapshotConnection() schema.SnapshotConnectionResolver {
|
|
return &snapshotConnectionResolver{r}
|
|
}
|
|
|
|
// StatementOfApplicability returns schema.StatementOfApplicabilityResolver implementation.
|
|
func (r *Resolver) StatementOfApplicability() schema.StatementOfApplicabilityResolver {
|
|
return &statementOfApplicabilityResolver{r}
|
|
}
|
|
|
|
// StatementOfApplicabilityConnection returns schema.StatementOfApplicabilityConnectionResolver implementation.
|
|
func (r *Resolver) StatementOfApplicabilityConnection() schema.StatementOfApplicabilityConnectionResolver {
|
|
return &statementOfApplicabilityConnectionResolver{r}
|
|
}
|
|
|
|
// Task returns schema.TaskResolver implementation.
|
|
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
|
|
|
|
// TaskConnection returns schema.TaskConnectionResolver implementation.
|
|
func (r *Resolver) TaskConnection() schema.TaskConnectionResolver { return &taskConnectionResolver{r} }
|
|
|
|
// TransferImpactAssessment returns schema.TransferImpactAssessmentResolver implementation.
|
|
func (r *Resolver) TransferImpactAssessment() schema.TransferImpactAssessmentResolver {
|
|
return &transferImpactAssessmentResolver{r}
|
|
}
|
|
|
|
// TransferImpactAssessmentConnection returns schema.TransferImpactAssessmentConnectionResolver implementation.
|
|
func (r *Resolver) TransferImpactAssessmentConnection() schema.TransferImpactAssessmentConnectionResolver {
|
|
return &transferImpactAssessmentConnectionResolver{r}
|
|
}
|
|
|
|
// TrustCenter returns schema.TrustCenterResolver implementation.
|
|
func (r *Resolver) TrustCenter() schema.TrustCenterResolver { return &trustCenterResolver{r} }
|
|
|
|
// TrustCenterAccess returns schema.TrustCenterAccessResolver implementation.
|
|
func (r *Resolver) TrustCenterAccess() schema.TrustCenterAccessResolver {
|
|
return &trustCenterAccessResolver{r}
|
|
}
|
|
|
|
// TrustCenterDocumentAccess returns schema.TrustCenterDocumentAccessResolver implementation.
|
|
func (r *Resolver) TrustCenterDocumentAccess() schema.TrustCenterDocumentAccessResolver {
|
|
return &trustCenterDocumentAccessResolver{r}
|
|
}
|
|
|
|
// TrustCenterDocumentAccessConnection returns schema.TrustCenterDocumentAccessConnectionResolver implementation.
|
|
func (r *Resolver) TrustCenterDocumentAccessConnection() schema.TrustCenterDocumentAccessConnectionResolver {
|
|
return &trustCenterDocumentAccessConnectionResolver{r}
|
|
}
|
|
|
|
// TrustCenterFile returns schema.TrustCenterFileResolver implementation.
|
|
func (r *Resolver) TrustCenterFile() schema.TrustCenterFileResolver {
|
|
return &trustCenterFileResolver{r}
|
|
}
|
|
|
|
// TrustCenterFileConnection returns schema.TrustCenterFileConnectionResolver implementation.
|
|
func (r *Resolver) TrustCenterFileConnection() schema.TrustCenterFileConnectionResolver {
|
|
return &trustCenterFileConnectionResolver{r}
|
|
}
|
|
|
|
// TrustCenterReference returns schema.TrustCenterReferenceResolver implementation.
|
|
func (r *Resolver) TrustCenterReference() schema.TrustCenterReferenceResolver {
|
|
return &trustCenterReferenceResolver{r}
|
|
}
|
|
|
|
// TrustCenterReferenceConnection returns schema.TrustCenterReferenceConnectionResolver implementation.
|
|
func (r *Resolver) TrustCenterReferenceConnection() schema.TrustCenterReferenceConnectionResolver {
|
|
return &trustCenterReferenceConnectionResolver{r}
|
|
}
|
|
|
|
// Vendor returns schema.VendorResolver implementation.
|
|
func (r *Resolver) Vendor() schema.VendorResolver { return &vendorResolver{r} }
|
|
|
|
// VendorBusinessAssociateAgreement returns schema.VendorBusinessAssociateAgreementResolver implementation.
|
|
func (r *Resolver) VendorBusinessAssociateAgreement() schema.VendorBusinessAssociateAgreementResolver {
|
|
return &vendorBusinessAssociateAgreementResolver{r}
|
|
}
|
|
|
|
// VendorComplianceReport returns schema.VendorComplianceReportResolver implementation.
|
|
func (r *Resolver) VendorComplianceReport() schema.VendorComplianceReportResolver {
|
|
return &vendorComplianceReportResolver{r}
|
|
}
|
|
|
|
// VendorConnection returns schema.VendorConnectionResolver implementation.
|
|
func (r *Resolver) VendorConnection() schema.VendorConnectionResolver {
|
|
return &vendorConnectionResolver{r}
|
|
}
|
|
|
|
// VendorContact returns schema.VendorContactResolver implementation.
|
|
func (r *Resolver) VendorContact() schema.VendorContactResolver { return &vendorContactResolver{r} }
|
|
|
|
// VendorDataPrivacyAgreement returns schema.VendorDataPrivacyAgreementResolver implementation.
|
|
func (r *Resolver) VendorDataPrivacyAgreement() schema.VendorDataPrivacyAgreementResolver {
|
|
return &vendorDataPrivacyAgreementResolver{r}
|
|
}
|
|
|
|
// VendorRiskAssessment returns schema.VendorRiskAssessmentResolver implementation.
|
|
func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver {
|
|
return &vendorRiskAssessmentResolver{r}
|
|
}
|
|
|
|
// VendorService returns schema.VendorServiceResolver implementation.
|
|
func (r *Resolver) VendorService() schema.VendorServiceResolver { return &vendorServiceResolver{r} }
|
|
|
|
// Viewer returns schema.ViewerResolver implementation.
|
|
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
|
|
|
|
// WebhookEventConnection returns schema.WebhookEventConnectionResolver implementation.
|
|
func (r *Resolver) WebhookEventConnection() schema.WebhookEventConnectionResolver {
|
|
return &webhookEventConnectionResolver{r}
|
|
}
|
|
|
|
// WebhookSubscription returns schema.WebhookSubscriptionResolver implementation.
|
|
func (r *Resolver) WebhookSubscription() schema.WebhookSubscriptionResolver {
|
|
return &webhookSubscriptionResolver{r}
|
|
}
|
|
|
|
// WebhookSubscriptionConnection returns schema.WebhookSubscriptionConnectionResolver implementation.
|
|
func (r *Resolver) WebhookSubscriptionConnection() schema.WebhookSubscriptionConnectionResolver {
|
|
return &webhookSubscriptionConnectionResolver{r}
|
|
}
|
|
|
|
type accessEntryResolver struct{ *Resolver }
|
|
type accessEntryConnectionResolver struct{ *Resolver }
|
|
type accessReviewResolver struct{ *Resolver }
|
|
type accessReviewCampaignResolver struct{ *Resolver }
|
|
type accessReviewCampaignConnectionResolver struct{ *Resolver }
|
|
type accessReviewCampaignScopeSourceResolver struct{ *Resolver }
|
|
type accessSourceResolver struct{ *Resolver }
|
|
type accessSourceConnectionResolver struct{ *Resolver }
|
|
type applicabilityStatementResolver struct{ *Resolver }
|
|
type applicabilityStatementConnectionResolver struct{ *Resolver }
|
|
type assetResolver struct{ *Resolver }
|
|
type assetConnectionResolver struct{ *Resolver }
|
|
type auditResolver struct{ *Resolver }
|
|
type auditConnectionResolver struct{ *Resolver }
|
|
type auditLogEntryResolver struct{ *Resolver }
|
|
type auditLogEntryConnectionResolver struct{ *Resolver }
|
|
type complianceExternalURLResolver struct{ *Resolver }
|
|
type complianceFrameworkResolver struct{ *Resolver }
|
|
type connectorResolver struct{ *Resolver }
|
|
type controlResolver struct{ *Resolver }
|
|
type controlConnectionResolver struct{ *Resolver }
|
|
type customDomainResolver struct{ *Resolver }
|
|
type dataProtectionImpactAssessmentResolver struct{ *Resolver }
|
|
type dataProtectionImpactAssessmentConnectionResolver struct{ *Resolver }
|
|
type datumResolver struct{ *Resolver }
|
|
type datumConnectionResolver struct{ *Resolver }
|
|
type documentResolver struct{ *Resolver }
|
|
type documentConnectionResolver struct{ *Resolver }
|
|
type documentVersionResolver struct{ *Resolver }
|
|
type documentVersionApprovalDecisionResolver struct{ *Resolver }
|
|
type documentVersionApprovalDecisionConnectionResolver struct{ *Resolver }
|
|
type documentVersionApprovalQuorumResolver struct{ *Resolver }
|
|
type documentVersionApprovalQuorumConnectionResolver struct{ *Resolver }
|
|
type documentVersionConnectionResolver struct{ *Resolver }
|
|
type documentVersionSignatureResolver struct{ *Resolver }
|
|
type documentVersionSignatureConnectionResolver struct{ *Resolver }
|
|
type electronicSignatureResolver struct{ *Resolver }
|
|
type employeeDocumentResolver struct{ *Resolver }
|
|
type employeeDocumentVersionResolver struct{ *Resolver }
|
|
type evidenceResolver struct{ *Resolver }
|
|
type evidenceConnectionResolver struct{ *Resolver }
|
|
type fileResolver struct{ *Resolver }
|
|
type findingResolver struct{ *Resolver }
|
|
type findingConnectionResolver struct{ *Resolver }
|
|
type frameworkResolver struct{ *Resolver }
|
|
type frameworkConnectionResolver struct{ *Resolver }
|
|
type mailingListResolver struct{ *Resolver }
|
|
type mailingListSubscriberConnectionResolver struct{ *Resolver }
|
|
type mailingListUpdateConnectionResolver struct{ *Resolver }
|
|
type measureResolver struct{ *Resolver }
|
|
type measureConnectionResolver struct{ *Resolver }
|
|
type meetingResolver struct{ *Resolver }
|
|
type meetingConnectionResolver struct{ *Resolver }
|
|
type mutationResolver struct{ *Resolver }
|
|
type obligationResolver struct{ *Resolver }
|
|
type obligationConnectionResolver struct{ *Resolver }
|
|
type organizationResolver struct{ *Resolver }
|
|
type processingActivityResolver struct{ *Resolver }
|
|
type processingActivityConnectionResolver struct{ *Resolver }
|
|
type profileResolver struct{ *Resolver }
|
|
type profileConnectionResolver struct{ *Resolver }
|
|
type queryResolver struct{ *Resolver }
|
|
type reportResolver struct{ *Resolver }
|
|
type rightsRequestResolver struct{ *Resolver }
|
|
type rightsRequestConnectionResolver struct{ *Resolver }
|
|
type riskResolver struct{ *Resolver }
|
|
type riskConnectionResolver struct{ *Resolver }
|
|
type slackConnectionResolver struct{ *Resolver }
|
|
type snapshotResolver struct{ *Resolver }
|
|
type snapshotConnectionResolver struct{ *Resolver }
|
|
type statementOfApplicabilityResolver struct{ *Resolver }
|
|
type statementOfApplicabilityConnectionResolver struct{ *Resolver }
|
|
type taskResolver struct{ *Resolver }
|
|
type taskConnectionResolver struct{ *Resolver }
|
|
type transferImpactAssessmentResolver struct{ *Resolver }
|
|
type transferImpactAssessmentConnectionResolver struct{ *Resolver }
|
|
type trustCenterResolver struct{ *Resolver }
|
|
type trustCenterAccessResolver struct{ *Resolver }
|
|
type trustCenterDocumentAccessResolver struct{ *Resolver }
|
|
type trustCenterDocumentAccessConnectionResolver struct{ *Resolver }
|
|
type trustCenterFileResolver struct{ *Resolver }
|
|
type trustCenterFileConnectionResolver struct{ *Resolver }
|
|
type trustCenterReferenceResolver struct{ *Resolver }
|
|
type trustCenterReferenceConnectionResolver struct{ *Resolver }
|
|
type vendorResolver struct{ *Resolver }
|
|
type vendorBusinessAssociateAgreementResolver struct{ *Resolver }
|
|
type vendorComplianceReportResolver struct{ *Resolver }
|
|
type vendorConnectionResolver struct{ *Resolver }
|
|
type vendorContactResolver struct{ *Resolver }
|
|
type vendorDataPrivacyAgreementResolver struct{ *Resolver }
|
|
type vendorRiskAssessmentResolver struct{ *Resolver }
|
|
type vendorServiceResolver struct{ *Resolver }
|
|
type viewerResolver struct{ *Resolver }
|
|
type webhookEventConnectionResolver struct{ *Resolver }
|
|
type webhookSubscriptionResolver struct{ *Resolver }
|
|
type webhookSubscriptionConnectionResolver struct{ *Resolver }
|