The console previously dispatched per-provider logic through a fan of init()-side-effect maps (driver names, OAuth2 metadata, probe URLs, display names, settings switches), spread across pkg/connector, pkg/accessreview/drivers and the console v1 resolvers. Adding a new provider required edits in every one of those places and a corresponding switch arm in CreateConnectorRequest. The same per-provider knowledge also leaked into Helm templates as hand-rolled environment-variable blocks per connector. This commit collapses the dispatch surface into a single typed *provider.Registry. The registry is constructed once by NewBuiltinRegistry at probod startup and threaded as an explicit dependency into every consumer (accessreview service, console v1 resolver, OAuth2 wiring). There is no package-level state. Each provider lives in one file under pkg/connector/provider/ that exposes a private xxxRegistration() *Registration constructor; NewBuiltinRegistry enumerates them. CreateConnectorRequest loses its per-provider settings fields and takes a single RawSettings json.RawMessage produced by the per-provider MarshalSettings closure. The 1Password SCIM bridge URL is validated at create time (http(s) scheme + non-empty host) so a malformed value fails fast at the resolver boundary. The Helm chart gains probo.connectorEnv and probo.connectorSecretEntries templates so adding a connector requires zero Helm changes. Access-review name resolution moves into the same Registration value to keep one authoritative dispatch table. Tests cover every Registration (DisplayName, NewDriver wired), Register error paths (nil, empty Provider, empty DisplayName, duplicate), All / ProviderDisplayName / ProviderOAuth2Scopes / ProbeURL hit and miss paths, the ApplyOAuth2Defaults templating and PKCE branches, and ConnectorSettings[T] round-trip plus malformed-JSON error path. The pre-refactor ApplyProviderDefaults test in pkg/connector is replaced by the equivalent in pkg/connector/provider. Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
1430 lines
48 KiB
Go
1430 lines
48 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.90
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"go.gearno.de/kit/log"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
"go.probo.inc/probo/pkg/gid"
|
|
"go.probo.inc/probo/pkg/iam"
|
|
"go.probo.inc/probo/pkg/page"
|
|
"go.probo.inc/probo/pkg/probo"
|
|
"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"
|
|
)
|
|
|
|
// UpdateOrganizationContext is the resolver for the updateOrganizationContext field.
|
|
func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input types.UpdateOrganizationContextInput) (*types.UpdateOrganizationContextPayload, error) {
|
|
scope, err := r.authorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Organizations.UpdateContext(ctx, scope, 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
|
|
}
|
|
|
|
// LogoURL is the resolver for the logoUrl field.
|
|
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetLogoUrl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
logoURL, err := r.probo.Organizations.GenerateLogoURL(ctx, scope, 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGetHorizontalLogoUrl)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
horizontalLogoURL, err := r.probo.Organizations.GenerateHorizontalLogoURL(ctx, scope, 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationContextGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
orgContext, err := r.probo.Organizations.GetContext(ctx, scope, 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.ContractEnded).WithMembership()
|
|
if filter.State != nil {
|
|
filters.WithState(*filter.State)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// MeasureCategories is the resolver for the measureCategories field.
|
|
func (r *organizationResolver) MeasureCategories(ctx context.Context, obj *types.Organization) ([]string, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionMeasureList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
categories, err := r.probo.Measures.ListDistinctCategoriesForOrganizationID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list measure categories", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return categories, 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionAccessSourceList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionAccessReviewCampaignList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// AssetListDocument is the resolver for the assetListDocument field.
|
|
func (r *organizationResolver) AssetListDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
assetDocumentID, err := r.probo.GeneratedDocuments.GetAssetListDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get asset list document ID: %w", err)
|
|
}
|
|
|
|
if assetDocumentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
doc, err := r.probo.Documents.Get(ctx, scope, *assetDocumentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get asset list document: %w", err)
|
|
}
|
|
|
|
return types.NewDocument(doc), 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) (*types.AssetConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionAssetList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.Assets.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), nil
|
|
}
|
|
|
|
// DataListDocument is the resolver for the dataListDocument field.
|
|
func (r *organizationResolver) DataListDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dataDocumentID, err := r.probo.GeneratedDocuments.GetDataListDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get data export document ID: %w", err)
|
|
}
|
|
|
|
if dataDocumentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
doc, err := r.probo.Documents.Get(ctx, scope, *dataDocumentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get data export document: %w", err)
|
|
}
|
|
|
|
return types.NewDocument(doc), nil
|
|
}
|
|
|
|
// Data is the resolver for the data field.
|
|
func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy) (*types.DatumConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDatumList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.Data.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionAuditList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Audits.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// FindingsDocument is the resolver for the findingsDocument field.
|
|
func (r *organizationResolver) FindingsDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
findingDocumentID, err := r.probo.GeneratedDocuments.GetFindingsDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get finding list document ID: %w", err)
|
|
}
|
|
|
|
if findingDocumentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
doc, err := r.probo.Documents.Get(ctx, scope, *findingDocumentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get finding list document: %w", err)
|
|
}
|
|
|
|
return types.NewDocument(doc), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionFindingList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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(kind, status, priority, ownerID)
|
|
|
|
page, err := r.probo.Findings.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionSlackConnectionList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Connectors.ListForOrganizationID(ctx, scope, 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionConnectorList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
connectors, err := r.probo.Connectors.ListAllForOrganizationID(ctx, scope, 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 _, p := range coredata.ConnectorProviders() {
|
|
_, oauthErr := r.connectorRegistry.Get(string(p))
|
|
|
|
scopes := r.providerRegistry.ProviderOAuth2Scopes(p)
|
|
if scopes == nil {
|
|
scopes = []string{}
|
|
}
|
|
|
|
info := &types.ConnectorProviderInfo{
|
|
Provider: p,
|
|
DisplayName: r.providerDisplayName(p),
|
|
OauthConfigured: oauthErr == nil,
|
|
APIKeySupported: r.providerSupportsAPIKey(p),
|
|
ClientCredentialsSupported: r.providerSupportsClientCredentials(p),
|
|
Oauth2Scopes: scopes,
|
|
ExtraSettings: r.providerExtraSettings(p),
|
|
}
|
|
infos = append(infos, info)
|
|
}
|
|
|
|
return infos, 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionControlList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Controls.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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) (*types.StatementOfApplicabilityConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionStatementOfApplicabilityList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.StatementsOfApplicability.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), 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) (*types.DataProtectionImpactAssessmentConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.DataProtectionImpactAssessments.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), nil
|
|
}
|
|
|
|
// DataProtectionImpactAssessmentsDocument is the resolver for the dataProtectionImpactAssessmentsDocument field.
|
|
func (r *organizationResolver) DataProtectionImpactAssessmentsDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
documentID, err := r.probo.GeneratedDocuments.GetDataProtectionImpactAssessmentsDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get DPIA list document ID", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if documentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
document, err := r.probo.Documents.Get(ctx, scope, *documentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load DPIA list document", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), 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) (*types.TransferImpactAssessmentConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.TransferImpactAssessments.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), nil
|
|
}
|
|
|
|
// TransferImpactAssessmentsDocument is the resolver for the transferImpactAssessmentsDocument field.
|
|
func (r *organizationResolver) TransferImpactAssessmentsDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
documentID, err := r.probo.GeneratedDocuments.GetTransferImpactAssessmentsDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get TIA list document ID", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if documentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
document, err := r.probo.Documents.Get(ctx, scope, *documentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load TIA list document", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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).
|
|
WithWriteModes(filter.WriteModes).
|
|
WithDocumentTypes(filter.DocumentTypes).
|
|
WithClassifications(filter.Classifications).
|
|
WithStatus(filter.Status)
|
|
}
|
|
|
|
page, err := r.probo.Documents.ListByOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionFrameworkList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Frameworks.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionMeasureList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Measures.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// ObligationsDocument is the resolver for the obligationsDocument field.
|
|
func (r *organizationResolver) ObligationsDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
obligationDocumentID, err := r.probo.GeneratedDocuments.GetObligationsDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get obligation list document ID: %w", err)
|
|
}
|
|
|
|
if obligationDocumentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
doc, err := r.probo.Documents.Get(ctx, scope, *obligationDocumentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot get obligation list document: %w", err)
|
|
}
|
|
|
|
return types.NewDocument(doc), 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) (*types.ObligationConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionObligationList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.Obligations.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), 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) (*types.ProcessingActivityConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionProcessingActivityList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
|
|
page, err := r.probo.ProcessingActivities.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
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), nil
|
|
}
|
|
|
|
// ProcessingActivitiesDocument is the resolver for the processingActivitiesDocument field.
|
|
func (r *organizationResolver) ProcessingActivitiesDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
documentID, err := r.probo.GeneratedDocuments.GetProcessingActivitiesDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get processing activities document ID", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if documentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
document, err := r.probo.Documents.Get(ctx, scope, *documentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load processing activities document", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionRightsRequestList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.RightsRequests.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionRiskList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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)
|
|
if filter != nil {
|
|
riskFilter = coredata.NewRiskFilter(filter.Query)
|
|
}
|
|
|
|
page, err := r.probo.Risks.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// RisksDocument is the resolver for the risksDocument field.
|
|
func (r *organizationResolver) RisksDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
documentID, err := r.probo.GeneratedDocuments.GetRisksDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get risks document ID", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if documentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
document, err := r.probo.Documents.Get(ctx, scope, *documentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load risks document", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), nil
|
|
}
|
|
|
|
// RiskAssessments is the resolver for the riskAssessments field.
|
|
func (r *organizationResolver) RiskAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskAssessmentOrderBy) (*types.RiskAssessmentConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionRiskAssessmentList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.RiskAssessmentOrderField]{
|
|
Field: coredata.RiskAssessmentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.RiskAssessmentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.riskManagement.ListForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk assessments", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRiskAssessmentConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// RiskAssessmentScenarios is the resolver for the riskAssessmentScenarios field.
|
|
func (r *organizationResolver) RiskAssessmentScenarios(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskAssessmentScenarioOrderBy) (*types.RiskAssessmentScenarioConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionRiskAssessmentScenarioList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.RiskAssessmentScenarioOrderField]{
|
|
Field: coredata.RiskAssessmentScenarioOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.RiskAssessmentScenarioOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.riskManagement.ListScenariosForOrganizationID(ctx, scope, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list risk scenarios", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewRiskAssessmentScenarioConnection(p, r, obj.ID), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionTaskList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.Tasks.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// TrustCenter is the resolver for the trustCenter field.
|
|
func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
trustCenter, err := r.probo.TrustCenters.GetByOrganizationID(ctx, scope, 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 = r.probo.Files.Get(ctx, scope, *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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionCustomDomainGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
domain, err := r.probo.CustomDomains.GetOrganizationCustomDomain(ctx, scope, 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
|
|
}
|
|
|
|
// 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterFileList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.TrustCenterFiles.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// CookieBanners is the resolver for the cookieBanners field.
|
|
func (r *organizationResolver) CookieBanners(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.CookieBannerOrderBy) (*types.CookieBannerConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionCookieBannerList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.CookieBannerOrderField]{
|
|
Field: coredata.CookieBannerOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.CookieBannerOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
banners, err := r.cookieBanner.ListCookieBannersForOrganization(ctx, scope, obj.ID, cursor, coredata.NewCookieBannerFilter(nil))
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list cookie banners", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
p := page.NewPage(banners, cursor)
|
|
|
|
return types.NewCookieBannerConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// ThirdParties is the resolver for the thirdParties field.
|
|
func (r *organizationResolver) ThirdParties(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ThirdPartyOrderBy, filter *types.ThirdPartyFilter) (*types.ThirdPartyConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionThirdPartyList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ThirdPartyOrderField]{
|
|
Field: coredata.ThirdPartyOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ThirdPartyOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
var (
|
|
firstLevel *bool
|
|
query *string
|
|
)
|
|
if filter != nil {
|
|
firstLevel = filter.FirstLevel
|
|
query = filter.Query
|
|
}
|
|
|
|
thirdPartyFilter := coredata.NewThirdPartyFilter(nil, firstLevel, query)
|
|
|
|
page, err := r.probo.ThirdParties.ListForOrganizationID(ctx, scope, obj.ID, cursor, thirdPartyFilter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list organization thirdParties", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewThirdPartyConnection(page, r, obj.ID, thirdPartyFilter), nil
|
|
}
|
|
|
|
// ThirdPartiesDocument is the resolver for the thirdPartiesDocument field.
|
|
func (r *organizationResolver) ThirdPartiesDocument(ctx context.Context, obj *types.Organization) (*types.Document, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
documentID, err := r.probo.GeneratedDocuments.GetThirdPartiesDocumentID(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get thirdParties document ID", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if documentID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
document, err := r.probo.Documents.Get(ctx, scope, *documentID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load thirdParties document", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDocument(document), 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) {
|
|
scope, err := r.authorize(ctx, obj.ID, probo.ActionWebhookSubscriptionList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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 := r.probo.WebhookSubscriptions.ListForOrganizationID(ctx, scope, 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
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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:
|
|
scope := coredata.NewScopeFromObjectID(obj.ParentID)
|
|
|
|
count, err := r.probo.Documents.CountVersionApprovers(ctx, scope, 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)
|
|
}
|
|
|
|
// Organization returns schema.OrganizationResolver implementation.
|
|
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{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}
|
|
}
|
|
|
|
type organizationResolver struct{ *Resolver }
|
|
type profileResolver struct{ *Resolver }
|
|
type profileConnectionResolver struct{ *Resolver }
|