From 5f93071b20912d2ceaf842a0800e35c4e44b7420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Tue, 14 Apr 2026 18:02:38 +0400 Subject: [PATCH] Consolidate hub type definitions into their own files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move Organization, Identity, TrustCenter, and Viewer definitions to include all their connection fields directly, removing all extend type blocks for these hub types from entity files. This eliminates the Relay schemaExtensions constraint where extend type could only target types defined in the main schema file. Entity files now only define their own standalone types and extend type Mutation. Signed-off-by: Émile Ré --- .../api/connect/v1/audit_log.resolvers.go | 47 - pkg/server/api/connect/v1/base.resolvers.go | 172 ++- .../api/connect/v1/graphql/audit_log.graphql | 11 - .../api/connect/v1/graphql/base.graphql | 43 +- .../connect/v1/graphql/organization.graphql | 46 + .../v1/graphql/personal_api_key.graphql | 9 - .../api/connect/v1/graphql/profile.graphql | 21 - .../api/connect/v1/graphql/saml.graphql | 9 - .../api/connect/v1/graphql/scim.graphql | 5 - .../api/connect/v1/graphql/session.graphql | 10 - .../api/connect/v1/organization.resolvers.go | 209 ++++ .../connect/v1/personal_api_key.resolvers.go | 31 - .../api/connect/v1/profile.resolvers.go | 82 -- pkg/server/api/connect/v1/saml.resolvers.go | 31 - pkg/server/api/connect/v1/scim.resolvers.go | 31 - .../api/connect/v1/session.resolvers.go | 39 - .../v1/access_review_campaign.resolvers.go | 58 - pkg/server/api/console/v1/asset.resolvers.go | 70 -- pkg/server/api/console/v1/audit.resolvers.go | 79 -- .../api/console/v1/audit_log.resolvers.go | 46 - pkg/server/api/console/v1/base.resolvers.go | 274 +++-- .../api/console/v1/connector.resolvers.go | 92 -- .../api/console/v1/control.resolvers.go | 70 -- ..._protection_impact_assessment.resolvers.go | 73 -- .../api/console/v1/document.resolvers.go | 196 --- .../api/console/v1/evidence.resolvers.go | 7 - .../api/console/v1/framework.resolvers.go | 30 - .../v1/graphql/access_review_campaign.graphql | 18 - .../api/console/v1/graphql/asset.graphql | 20 - .../api/console/v1/graphql/audit.graphql | 19 - .../api/console/v1/graphql/audit_log.graphql | 11 - .../api/console/v1/graphql/base.graphql | 35 +- .../api/console/v1/graphql/connector.graphql | 12 - .../api/console/v1/graphql/control.graphql | 20 - .../data_protection_impact_assessment.graphql | 20 - .../api/console/v1/graphql/document.graphql | 35 - .../api/console/v1/graphql/evidence.graphql | 10 - .../api/console/v1/graphql/framework.graphql | 10 - .../api/console/v1/graphql/measure.graphql | 11 - .../api/console/v1/graphql/meeting.graphql | 10 - .../api/console/v1/graphql/obligation.graphql | 11 - .../console/v1/graphql/organization.graphql | 255 ++++ .../v1/graphql/processing_activity.graphql | 11 - .../console/v1/graphql/rights_request.graphql | 10 - .../api/console/v1/graphql/risk.graphql | 11 - .../api/console/v1/graphql/snapshot.graphql | 10 - .../api/console/v1/graphql/task.graphql | 10 - .../console/v1/graphql/trust_center.graphql | 12 - .../api/console/v1/graphql/vendor.graphql | 11 - .../api/console/v1/graphql/webhook.graphql | 10 - .../api/console/v1/measure.resolvers.go | 35 - .../api/console/v1/meeting.resolvers.go | 31 - .../api/console/v1/obligation.resolvers.go | 37 - .../api/console/v1/organization.resolvers.go | 1084 +++++++++++++++++ .../v1/processing_activity.resolvers.go | 36 - .../console/v1/rights_request.resolvers.go | 32 - pkg/server/api/console/v1/risk.resolvers.go | 35 - .../api/console/v1/snapshot.resolvers.go | 30 - pkg/server/api/console/v1/task.resolvers.go | 30 - .../api/console/v1/trust_center.resolvers.go | 77 -- pkg/server/api/console/v1/vendor.resolvers.go | 35 - .../api/console/v1/webhook.resolvers.go | 30 - pkg/server/api/trust/v1/base.resolvers.go | 163 --- pkg/server/api/trust/v1/graphql/base.graphql | 59 - .../api/trust/v1/graphql/mailing_list.graphql | 11 - pkg/server/api/trust/v1/graphql/nda.graphql | 4 - .../api/trust/v1/graphql/trust_center.graphql | 70 ++ .../api/trust/v1/mailing_list.resolvers.go | 56 - pkg/server/api/trust/v1/nda.resolvers.go | 21 - .../api/trust/v1/trust_center.resolvers.go | 238 ++++ 70 files changed, 2208 insertions(+), 2279 deletions(-) diff --git a/pkg/server/api/connect/v1/audit_log.resolvers.go b/pkg/server/api/connect/v1/audit_log.resolvers.go index 03e6f9814..f09de64a5 100644 --- a/pkg/server/api/connect/v1/audit_log.resolvers.go +++ b/pkg/server/api/connect/v1/audit_log.resolvers.go @@ -10,12 +10,9 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" - "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) // Organization is the resolver for the organization field. @@ -44,50 +41,6 @@ func (r *auditLogEntryConnectionResolver) TotalCount(ctx context.Context, obj *t return count, 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, - } - } - - c := cursor.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, c, 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 -} - // AuditLogEntry returns schema.AuditLogEntryResolver implementation. func (r *Resolver) AuditLogEntry() schema.AuditLogEntryResolver { return &auditLogEntryResolver{r} } diff --git a/pkg/server/api/connect/v1/base.resolvers.go b/pkg/server/api/connect/v1/base.resolvers.go index 90529bc47..a9629e840 100644 --- a/pkg/server/api/connect/v1/base.resolvers.go +++ b/pkg/server/api/connect/v1/base.resolvers.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "strings" - "time" "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" @@ -19,13 +18,123 @@ import ( "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/iam" "go.probo.inc/probo/pkg/mail" + "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/authz" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" + "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) +// Profiles is the resolver for the profiles field. +func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, 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, authz.WithSkipAssumptionCheck()); err != nil { + return nil, err + } + + filters := coredata.NewMembershipProfileFilter(nil).WithMembership() + if filter != nil { + filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded).WithMembership() + if filter.State != nil { + filters.WithState(*filter.State) + } + } + + if gqlutils.OnlyTotalCountSelected(ctx) { + return &types.ProfileConnection{ + Resolver: r, + ParentID: obj.ID, + Filters: filters, + }, nil + } + + pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{ + Field: coredata.MembershipProfileOrderFieldFullName, + Direction: page.OrderDirectionAsc, + } + if orderBy != nil { + pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{ + Field: orderBy.Field, + Direction: orderBy.Direction, + } + } + + cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) + + page, err := r.iam.AccountService.ListProfilesForIdentity(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 +} + +// Sessions is the resolver for the sessions field. +func (r *identityResolver) Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionSessionList); err != nil { + return nil, err + } + + if gqlutils.OnlyTotalCountSelected(ctx) { + return &types.SessionConnection{ + Resolver: r, + ParentID: obj.ID, + }, nil + } + + pageOrderBy := page.OrderBy[coredata.SessionOrderField]{ + Field: coredata.SessionOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + if orderBy != nil { + pageOrderBy = page.OrderBy[coredata.SessionOrderField]{ + Field: orderBy.Field, + Direction: orderBy.Direction, + } + } + + cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) + + page, err := r.iam.AccountService.ListSessions(ctx, obj.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list sessions", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewSessionConnection(page, r, obj.ID), nil +} + +// PersonalAPIKeys is the resolver for the personalAPIKeys field. +func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionPersonalAPIKeyList); err != nil { + return nil, err + } + + if gqlutils.OnlyTotalCountSelected(ctx) { + return &types.PersonalAPIKeyConnection{ + Resolver: r, + ParentID: obj.ID, + }, nil + } + + pageOrderBy := page.OrderBy[coredata.PersonalAPIKeyOrderField]{ + Field: coredata.PersonalAPIKeyOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + + cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) + + page, err := r.iam.AccountService.ListPersonalAPIKeys(ctx, obj.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list personal api keys", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewPersonalAPIKeyConnection(page, r, obj.ID), nil +} + // SsoLoginURL is the resolver for the ssoLoginURL field. func (r *identityResolver) SsoLoginURL(ctx context.Context, obj *types.Identity) (*string, error) { if err := r.authorize(ctx, obj.ID, iam.ActionIdentityGet); err != nil { @@ -525,63 +634,6 @@ func (r *mutationResolver) RevokeAllSessions(ctx context.Context) (*types.Revoke return &types.RevokeAllSessionsPayload{RevokedCount: int(revokedCount)}, nil } -// 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, iam.ActionOrganizationGet, authz.WithSkipAssumptionCheck()); err != nil { - return nil, err - } - - presignedURL, err := r.iam.OrganizationService.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 presignedURL, 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, iam.ActionOrganizationGet); err != nil { - return nil, err - } - - presignedURL, err := r.iam.OrganizationService.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 presignedURL, nil -} - -// Viewer is the resolver for the viewer field. -func (r *organizationResolver) Viewer(ctx context.Context, obj *types.Organization) (*types.Profile, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil { - return nil, err - } - - identity := authn.IdentityFromContext(ctx) - - profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, obj.ID) - if err != nil { - var errNotFound *iam.ErrProfileNotFound - if errors.As(err, &errNotFound) { - 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 -} - -// 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) -} - // Node is the resolver for the node field. func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) { var ( @@ -797,13 +849,9 @@ func (r *Resolver) Identity() schema.IdentityResolver { return &identityResolver // Mutation returns schema.MutationResolver implementation. func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} } -// Organization returns schema.OrganizationResolver implementation. -func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} } - // Query returns schema.QueryResolver implementation. func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} } type identityResolver struct{ *Resolver } type mutationResolver struct{ *Resolver } -type organizationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } diff --git a/pkg/server/api/connect/v1/graphql/audit_log.graphql b/pkg/server/api/connect/v1/graphql/audit_log.graphql index 72286a37c..cfc88bda1 100644 --- a/pkg/server/api/connect/v1/graphql/audit_log.graphql +++ b/pkg/server/api/connect/v1/graphql/audit_log.graphql @@ -1,14 +1,3 @@ -extend type Organization { - auditLogEntries( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AuditLogEntryOrder - filter: AuditLogEntryFilter - ): AuditLogEntryConnection! @goField(forceResolver: true) -} - enum AuditLogActorType @goModel( model: "go.probo.inc/probo/pkg/coredata.AuditLogActorType" diff --git a/pkg/server/api/connect/v1/graphql/base.graphql b/pkg/server/api/connect/v1/graphql/base.graphql index d1e822fc5..1f90ecab3 100644 --- a/pkg/server/api/connect/v1/graphql/base.graphql +++ b/pkg/server/api/connect/v1/graphql/base.graphql @@ -66,6 +66,30 @@ type Identity implements Node { createdAt: Datetime! updatedAt: Datetime! + profiles( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ProfileOrder + filter: ProfileFilter + ): ProfileConnection @goField(forceResolver: true) + + sessions( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: SessionOrder + ): SessionConnection @goField(forceResolver: true) + + personalAPIKeys( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): PersonalAPIKeyConnection @goField(forceResolver: true) + ssoLoginURL: String @goField(forceResolver: true) @session(required: PRESENT) @@ -75,25 +99,6 @@ type Identity implements Node { @session(required: PRESENT) } -type Organization implements Node { - id: ID! - name: String! - logoUrl: String @goField(forceResolver: true) - horizontalLogoUrl: String @goField(forceResolver: true) - email: String - description: String - websiteUrl: String - headquarterAddress: String - createdAt: Datetime! - updatedAt: Datetime! - - viewer: Profile @goField(forceResolver: true) - - permission(action: String!): Boolean! - @goField(forceResolver: true) - @session(required: PRESENT) -} - type Mutation { signIn(input: SignInInput!): SignInPayload @session(required: OPTIONAL) signUp(input: SignUpInput!): SignUpPayload @session(required: NONE) diff --git a/pkg/server/api/connect/v1/graphql/organization.graphql b/pkg/server/api/connect/v1/graphql/organization.graphql index c395338f1..0247b1a4f 100644 --- a/pkg/server/api/connect/v1/graphql/organization.graphql +++ b/pkg/server/api/connect/v1/graphql/organization.graphql @@ -1,3 +1,49 @@ +type Organization implements Node { + id: ID! + name: String! + logoUrl: String @goField(forceResolver: true) + horizontalLogoUrl: String @goField(forceResolver: true) + email: String + description: String + websiteUrl: String + headquarterAddress: String + createdAt: Datetime! + updatedAt: Datetime! + + profiles( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ProfileOrder + ): ProfileConnection @goField(forceResolver: true) + + samlConfigurations( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): SAMLConfigurationConnection @goField(forceResolver: true) + + scimConfiguration: SCIMConfiguration @goField(forceResolver: true) + scimBridgeTypes: [SCIMBridgeTypeInfo!]! @goField(forceResolver: true) + + auditLogEntries( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AuditLogEntryOrder + filter: AuditLogEntryFilter + ): AuditLogEntryConnection! @goField(forceResolver: true) + + viewer: Profile @goField(forceResolver: true) + + permission(action: String!): Boolean! + @goField(forceResolver: true) + @session(required: PRESENT) +} + extend type Mutation { createOrganization( input: CreateOrganizationInput! diff --git a/pkg/server/api/connect/v1/graphql/personal_api_key.graphql b/pkg/server/api/connect/v1/graphql/personal_api_key.graphql index f47745020..9ac535182 100644 --- a/pkg/server/api/connect/v1/graphql/personal_api_key.graphql +++ b/pkg/server/api/connect/v1/graphql/personal_api_key.graphql @@ -1,12 +1,3 @@ -extend type Identity { - personalAPIKeys( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): PersonalAPIKeyConnection @goField(forceResolver: true) -} - type PersonalAPIKey implements Node { id: ID! name: String! diff --git a/pkg/server/api/connect/v1/graphql/profile.graphql b/pkg/server/api/connect/v1/graphql/profile.graphql index f27688ebc..5444a2a03 100644 --- a/pkg/server/api/connect/v1/graphql/profile.graphql +++ b/pkg/server/api/connect/v1/graphql/profile.graphql @@ -1,24 +1,3 @@ -extend type Identity { - profiles( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: ProfileOrder - filter: ProfileFilter - ): ProfileConnection @goField(forceResolver: true) -} - -extend type Organization { - profiles( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: ProfileOrder - ): ProfileConnection @goField(forceResolver: true) -} - type Profile implements Node { id: ID! fullName: String! diff --git a/pkg/server/api/connect/v1/graphql/saml.graphql b/pkg/server/api/connect/v1/graphql/saml.graphql index 7a46c4a09..ece26a74e 100644 --- a/pkg/server/api/connect/v1/graphql/saml.graphql +++ b/pkg/server/api/connect/v1/graphql/saml.graphql @@ -1,12 +1,3 @@ -extend type Organization { - samlConfigurations( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): SAMLConfigurationConnection @goField(forceResolver: true) -} - type SAMLConfiguration implements Node { id: ID! emailDomain: String! diff --git a/pkg/server/api/connect/v1/graphql/scim.graphql b/pkg/server/api/connect/v1/graphql/scim.graphql index a8eb7b4d0..cb76fbe3e 100644 --- a/pkg/server/api/connect/v1/graphql/scim.graphql +++ b/pkg/server/api/connect/v1/graphql/scim.graphql @@ -1,8 +1,3 @@ -extend type Organization { - scimConfiguration: SCIMConfiguration @goField(forceResolver: true) - scimBridgeTypes: [SCIMBridgeTypeInfo!]! @goField(forceResolver: true) -} - type SCIMConfiguration implements Node { id: ID! endpointUrl: String! @goField(forceResolver: true) diff --git a/pkg/server/api/connect/v1/graphql/session.graphql b/pkg/server/api/connect/v1/graphql/session.graphql index 29b04da72..54b4c3020 100644 --- a/pkg/server/api/connect/v1/graphql/session.graphql +++ b/pkg/server/api/connect/v1/graphql/session.graphql @@ -13,16 +13,6 @@ input SessionOrder { field: SessionOrderField! } -extend type Identity { - sessions( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: SessionOrder - ): SessionConnection @goField(forceResolver: true) -} - type Session implements Node { id: ID! identity: Identity @goField(forceResolver: true) diff --git a/pkg/server/api/connect/v1/organization.resolvers.go b/pkg/server/api/connect/v1/organization.resolvers.go index d8e31cbe6..242b1d4ef 100644 --- a/pkg/server/api/connect/v1/organization.resolvers.go +++ b/pkg/server/api/connect/v1/organization.resolvers.go @@ -9,13 +9,19 @@ import ( "context" "errors" "fmt" + "time" "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" + "go.probo.inc/probo/pkg/iam/scim/bridge/provider/googleworkspace" + "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" + "go.probo.inc/probo/pkg/server/api/authz" + "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" + "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) // CreateOrganization is the resolver for the createOrganization field. @@ -148,3 +154,206 @@ func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.D func (r *mutationResolver) DeleteOrganizationHorizontalLogo(ctx context.Context, input types.DeleteOrganizationHorizontalLogoInput) (*types.DeleteOrganizationHorizontalLogoPayload, error) { panic(fmt.Errorf("not implemented: DeleteOrganizationHorizontalLogo - deleteOrganizationHorizontalLogo")) } + +// 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, iam.ActionOrganizationGet, authz.WithSkipAssumptionCheck()); err != nil { + return nil, err + } + + presignedURL, err := r.iam.OrganizationService.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 presignedURL, 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, iam.ActionOrganizationGet); err != nil { + return nil, err + } + + presignedURL, err := r.iam.OrganizationService.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 presignedURL, 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) (*types.ProfileConnection, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil { + return nil, err + } + + filter := coredata.NewMembershipProfileFilter(nil).WithMembership() + + if gqlutils.OnlyTotalCountSelected(ctx) { + return &types.ProfileConnection{ + Resolver: r, + ParentID: obj.ID, + Filters: filter, + }, nil + } + + pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{ + Field: coredata.MembershipProfileOrderFieldFullName, + Direction: page.OrderDirectionAsc, + } + if orderBy != nil { + pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{ + Field: orderBy.Field, + Direction: orderBy.Direction, + } + } + + cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) + + page, err := r.iam.OrganizationService.ListProfiles(ctx, obj.ID, cursor, filter) + 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, filter), nil +} + +// SamlConfigurations is the resolver for the samlConfigurations field. +func (r *organizationResolver) SamlConfigurations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SAMLConfigurationConnection, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionSAMLConfigurationList); err != nil { + return nil, err + } + + if gqlutils.OnlyTotalCountSelected(ctx) { + return &types.SAMLConfigurationConnection{ + Resolver: r, + ParentID: obj.ID, + }, nil + } + + pageOrderBy := page.OrderBy[coredata.SAMLConfigurationOrderField]{ + Field: coredata.SAMLConfigurationOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + + cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) + + page, err := r.iam.OrganizationService.ListSAMLConfigurations(ctx, obj.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list saml configurations", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewSAMLConfigurationConnection(page, r, obj.ID), nil +} + +// ScimConfiguration is the resolver for the scimConfiguration field. +func (r *organizationResolver) ScimConfiguration(ctx context.Context, obj *types.Organization) (*types.SCIMConfiguration, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionSCIMConfigurationGet); err != nil { + return nil, err + } + + config, err := r.iam.OrganizationService.GetSCIMConfiguration(ctx, obj.ID) + if err != nil { + var notFound *iam.ErrNoSCIMConfigurationFound + if errors.As(err, ¬Found) { + return nil, nil + } + + r.logger.ErrorCtx(ctx, "cannot get scim configuration", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewSCIMConfiguration(config), nil +} + +// ScimBridgeTypes is the resolver for the scimBridgeTypes field. +func (r *organizationResolver) ScimBridgeTypes(ctx context.Context, obj *types.Organization) ([]*types.SCIMBridgeTypeInfo, error) { + return []*types.SCIMBridgeTypeInfo{ + { + Type: coredata.SCIMBridgeTypeGoogleWorkspace, + Oauth2Scopes: googleworkspace.OAuth2Scopes, + }, + }, 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, + } + } + + c := cursor.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, c, 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 +} + +// Viewer is the resolver for the viewer field. +func (r *organizationResolver) Viewer(ctx context.Context, obj *types.Organization) (*types.Profile, error) { + if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil { + return nil, err + } + + identity := authn.IdentityFromContext(ctx) + + profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, obj.ID) + if err != nil { + var errNotFound *iam.ErrProfileNotFound + if errors.As(err, &errNotFound) { + 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 +} + +// 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 returns schema.OrganizationResolver implementation. +func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} } + +type organizationResolver struct{ *Resolver } diff --git a/pkg/server/api/connect/v1/personal_api_key.resolvers.go b/pkg/server/api/connect/v1/personal_api_key.resolvers.go index 2a92e67a6..7edd8b8c0 100644 --- a/pkg/server/api/connect/v1/personal_api_key.resolvers.go +++ b/pkg/server/api/connect/v1/personal_api_key.resolvers.go @@ -11,43 +11,12 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" - "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) -// PersonalAPIKeys is the resolver for the personalAPIKeys field. -func (r *identityResolver) PersonalAPIKeys(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.PersonalAPIKeyConnection, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionPersonalAPIKeyList); err != nil { - return nil, err - } - - if gqlutils.OnlyTotalCountSelected(ctx) { - return &types.PersonalAPIKeyConnection{ - Resolver: r, - ParentID: obj.ID, - }, nil - } - - pageOrderBy := page.OrderBy[coredata.PersonalAPIKeyOrderField]{ - Field: coredata.PersonalAPIKeyOrderFieldCreatedAt, - Direction: page.OrderDirectionDesc, - } - - cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) - - page, err := r.iam.AccountService.ListPersonalAPIKeys(ctx, obj.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list personal api keys", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewPersonalAPIKeyConnection(page, r, obj.ID), nil -} - // CreatePersonalAPIKey is the resolver for the createPersonalAPIKey field. func (r *mutationResolver) CreatePersonalAPIKey(ctx context.Context, input types.CreatePersonalAPIKeyInput) (*types.CreatePersonalAPIKeyPayload, error) { identity := authn.IdentityFromContext(ctx) diff --git a/pkg/server/api/connect/v1/profile.resolvers.go b/pkg/server/api/connect/v1/profile.resolvers.go index c9438a49a..235d65ac7 100644 --- a/pkg/server/api/connect/v1/profile.resolvers.go +++ b/pkg/server/api/connect/v1/profile.resolvers.go @@ -21,50 +21,6 @@ import ( "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) -// Profiles is the resolver for the profiles field. -func (r *identityResolver) Profiles(ctx context.Context, obj *types.Identity, 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, authz.WithSkipAssumptionCheck()); err != nil { - return nil, err - } - - filters := coredata.NewMembershipProfileFilter(nil).WithMembership() - if filter != nil { - filters = coredata.NewMembershipProfileFilter(filter.ExcludeContractEnded).WithMembership() - if filter.State != nil { - filters.WithState(*filter.State) - } - } - - if gqlutils.OnlyTotalCountSelected(ctx) { - return &types.ProfileConnection{ - Resolver: r, - ParentID: obj.ID, - Filters: filters, - }, nil - } - - pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{ - Field: coredata.MembershipProfileOrderFieldFullName, - Direction: page.OrderDirectionAsc, - } - if orderBy != nil { - pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{ - Field: orderBy.Field, - Direction: orderBy.Direction, - } - } - - cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) - - page, err := r.iam.AccountService.ListProfilesForIdentity(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 -} - // Permission is the resolver for the permission field. func (r *invitationResolver) Permission(ctx context.Context, obj *types.Invitation, action string) (bool, error) { return r.Resolver.Permission(ctx, obj, action) @@ -268,44 +224,6 @@ func (r *mutationResolver) RemoveUser(ctx context.Context, input types.RemoveUse return &types.RemoveUserPayload{DeletedProfileID: input.ProfileID}, 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) (*types.ProfileConnection, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileList); err != nil { - return nil, err - } - - filter := coredata.NewMembershipProfileFilter(nil).WithMembership() - - if gqlutils.OnlyTotalCountSelected(ctx) { - return &types.ProfileConnection{ - Resolver: r, - ParentID: obj.ID, - Filters: filter, - }, nil - } - - pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{ - Field: coredata.MembershipProfileOrderFieldFullName, - Direction: page.OrderDirectionAsc, - } - if orderBy != nil { - pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{ - Field: orderBy.Field, - Direction: orderBy.Direction, - } - } - - cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) - - page, err := r.iam.OrganizationService.ListProfiles(ctx, obj.ID, cursor, filter) - 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, filter), nil -} - // Identity is the resolver for the identity field. func (r *profileResolver) Identity(ctx context.Context, obj *types.Profile) (*types.Identity, error) { if err := r.authorize( diff --git a/pkg/server/api/connect/v1/saml.resolvers.go b/pkg/server/api/connect/v1/saml.resolvers.go index c5a43daf4..9dd2b82f3 100644 --- a/pkg/server/api/connect/v1/saml.resolvers.go +++ b/pkg/server/api/connect/v1/saml.resolvers.go @@ -12,11 +12,9 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" - "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) // CreateSAMLConfiguration is the resolver for the createSAMLConfiguration field. @@ -116,35 +114,6 @@ func (r *mutationResolver) DeleteSAMLConfiguration(ctx context.Context, input ty return &types.DeleteSAMLConfigurationPayload{DeletedSamlConfigurationID: input.SamlConfigurationID}, nil } -// SamlConfigurations is the resolver for the samlConfigurations field. -func (r *organizationResolver) SamlConfigurations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SAMLConfigurationConnection, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionSAMLConfigurationList); err != nil { - return nil, err - } - - if gqlutils.OnlyTotalCountSelected(ctx) { - return &types.SAMLConfigurationConnection{ - Resolver: r, - ParentID: obj.ID, - }, nil - } - - pageOrderBy := page.OrderBy[coredata.SAMLConfigurationOrderField]{ - Field: coredata.SAMLConfigurationOrderFieldCreatedAt, - Direction: page.OrderDirectionDesc, - } - - cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) - - page, err := r.iam.OrganizationService.ListSAMLConfigurations(ctx, obj.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list saml configurations", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewSAMLConfigurationConnection(page, r, obj.ID), nil -} - // TestLoginURL is the resolver for the testLoginUrl field. func (r *sAMLConfigurationResolver) TestLoginURL(ctx context.Context, obj *types.SAMLConfiguration) (string, error) { return r.baseURL.WithPath("/api/connect/v1/saml/2.0/" + obj.ID.String()).MustString(), nil diff --git a/pkg/server/api/connect/v1/scim.resolvers.go b/pkg/server/api/connect/v1/scim.resolvers.go index 98c4bd512..dfa0be0b2 100644 --- a/pkg/server/api/connect/v1/scim.resolvers.go +++ b/pkg/server/api/connect/v1/scim.resolvers.go @@ -12,7 +12,6 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/iam/scim/bridge/provider/googleworkspace" "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" @@ -107,36 +106,6 @@ func (r *mutationResolver) UpdateSCIMBridge(ctx context.Context, input types.Upd }, nil } -// ScimConfiguration is the resolver for the scimConfiguration field. -func (r *organizationResolver) ScimConfiguration(ctx context.Context, obj *types.Organization) (*types.SCIMConfiguration, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionSCIMConfigurationGet); err != nil { - return nil, err - } - - config, err := r.iam.OrganizationService.GetSCIMConfiguration(ctx, obj.ID) - if err != nil { - var notFound *iam.ErrNoSCIMConfigurationFound - if errors.As(err, ¬Found) { - return nil, nil - } - - r.logger.ErrorCtx(ctx, "cannot get scim configuration", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewSCIMConfiguration(config), nil -} - -// ScimBridgeTypes is the resolver for the scimBridgeTypes field. -func (r *organizationResolver) ScimBridgeTypes(ctx context.Context, obj *types.Organization) ([]*types.SCIMBridgeTypeInfo, error) { - return []*types.SCIMBridgeTypeInfo{ - { - Type: coredata.SCIMBridgeTypeGoogleWorkspace, - Oauth2Scopes: googleworkspace.OAuth2Scopes, - }, - }, nil -} - // ScimConfiguration is the resolver for the scimConfiguration field. func (r *sCIMBridgeResolver) ScimConfiguration(ctx context.Context, obj *types.SCIMBridge) (*types.SCIMConfiguration, error) { if err := r.authorize(ctx, obj.ScimConfiguration.ID, iam.ActionSCIMConfigurationGet); err != nil { diff --git a/pkg/server/api/connect/v1/session.resolvers.go b/pkg/server/api/connect/v1/session.resolvers.go index b848f749b..aa7a65707 100644 --- a/pkg/server/api/connect/v1/session.resolvers.go +++ b/pkg/server/api/connect/v1/session.resolvers.go @@ -9,50 +9,11 @@ import ( "context" "go.gearno.de/kit/log" - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/connect/v1/schema" "go.probo.inc/probo/pkg/server/api/connect/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" - "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" ) -// Sessions is the resolver for the sessions field. -func (r *identityResolver) Sessions(ctx context.Context, obj *types.Identity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SessionOrder) (*types.SessionConnection, error) { - if err := r.authorize(ctx, obj.ID, iam.ActionSessionList); err != nil { - return nil, err - } - - if gqlutils.OnlyTotalCountSelected(ctx) { - return &types.SessionConnection{ - Resolver: r, - ParentID: obj.ID, - }, nil - } - - pageOrderBy := page.OrderBy[coredata.SessionOrderField]{ - Field: coredata.SessionOrderFieldCreatedAt, - Direction: page.OrderDirectionDesc, - } - if orderBy != nil { - pageOrderBy = page.OrderBy[coredata.SessionOrderField]{ - Field: orderBy.Field, - Direction: orderBy.Direction, - } - } - - cursor := cursor.NewCursor(first, after, last, before, pageOrderBy) - - page, err := r.iam.AccountService.ListSessions(ctx, obj.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list sessions", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewSessionConnection(page, r, obj.ID), nil -} - // Identity is the resolver for the identity field. func (r *sessionResolver) Identity(ctx context.Context, obj *types.Session) (*types.Identity, error) { if gqlutils.OnlyIDSelected(ctx) { diff --git a/pkg/server/api/console/v1/access_review_campaign.resolvers.go b/pkg/server/api/console/v1/access_review_campaign.resolvers.go index 8668bad66..db81d2dc5 100644 --- a/pkg/server/api/console/v1/access_review_campaign.resolvers.go +++ b/pkg/server/api/console/v1/access_review_campaign.resolvers.go @@ -955,64 +955,6 @@ func (r *mutationResolver) FlagAccessEntry(ctx context.Context, input types.Flag }, 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 -} - // AccessEntry returns schema.AccessEntryResolver implementation. func (r *Resolver) AccessEntry() schema.AccessEntryResolver { return &accessEntryResolver{r} } diff --git a/pkg/server/api/console/v1/asset.resolvers.go b/pkg/server/api/console/v1/asset.resolvers.go index 0f1d203a1..61c516bb3 100644 --- a/pkg/server/api/console/v1/asset.resolvers.go +++ b/pkg/server/api/console/v1/asset.resolvers.go @@ -405,76 +405,6 @@ func (r *mutationResolver) DeleteDatum(ctx context.Context, input types.DeleteDa }, 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 -} - // Asset returns schema.AssetResolver implementation. func (r *Resolver) Asset() schema.AssetResolver { return &assetResolver{r} } diff --git a/pkg/server/api/console/v1/audit.resolvers.go b/pkg/server/api/console/v1/audit.resolvers.go index 1ecde0d02..f9e5b2181 100644 --- a/pkg/server/api/console/v1/audit.resolvers.go +++ b/pkg/server/api/console/v1/audit.resolvers.go @@ -677,85 +677,6 @@ func (r *mutationResolver) DeleteFindingAuditMapping(ctx context.Context, input }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/audit_log.resolvers.go b/pkg/server/api/console/v1/audit_log.resolvers.go index 0e9fa4e1e..2f355f53b 100644 --- a/pkg/server/api/console/v1/audit_log.resolvers.go +++ b/pkg/server/api/console/v1/audit_log.resolvers.go @@ -10,8 +10,6 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/page" "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" @@ -43,50 +41,6 @@ func (r *auditLogEntryConnectionResolver) TotalCount(ctx context.Context, obj *t return count, 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 -} - // AuditLogEntry returns schema.AuditLogEntryResolver implementation. func (r *Resolver) AuditLogEntry() schema.AuditLogEntryResolver { return &auditLogEntryResolver{r} } diff --git a/pkg/server/api/console/v1/base.resolvers.go b/pkg/server/api/console/v1/base.resolvers.go index fdb906e3a..2bd0e9874 100644 --- a/pkg/server/api/console/v1/base.resolvers.go +++ b/pkg/server/api/console/v1/base.resolvers.go @@ -21,7 +21,6 @@ import ( "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/validator" ) @@ -73,117 +72,6 @@ func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input }, nil } -// 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 -} - -// 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 -} - -// 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) -} - // Node is the resolver for the node field. func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) { var ( @@ -543,15 +431,170 @@ func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) { return &types.Viewer{ID: viewerID}, nil } +// 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 +} + // File returns schema.FileResolver implementation. func (r *Resolver) File() schema.FileResolver { return &fileResolver{r} } // Mutation returns schema.MutationResolver implementation. func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} } -// Organization returns schema.OrganizationResolver implementation. -func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} } - // Query returns schema.QueryResolver implementation. func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} } @@ -560,6 +603,5 @@ func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} } type fileResolver struct{ *Resolver } type mutationResolver struct{ *Resolver } -type organizationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } type viewerResolver struct{ *Resolver } diff --git a/pkg/server/api/console/v1/connector.resolvers.go b/pkg/server/api/console/v1/connector.resolvers.go index 43bd3b540..22e26a7ea 100644 --- a/pkg/server/api/console/v1/connector.resolvers.go +++ b/pkg/server/api/console/v1/connector.resolvers.go @@ -14,12 +14,10 @@ import ( "go.probo.inc/probo/pkg/accessreview/drivers" "go.probo.inc/probo/pkg/connector" "go.probo.inc/probo/pkg/coredata" - "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/slack" ) // Oauth2Scopes is the resolver for the oauth2Scopes field. @@ -167,96 +165,6 @@ func (r *mutationResolver) DeleteSlackConnection(ctx context.Context, input type }, 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 -} - // 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) diff --git a/pkg/server/api/console/v1/control.resolvers.go b/pkg/server/api/console/v1/control.resolvers.go index ee5125179..4b1cf1b43 100644 --- a/pkg/server/api/console/v1/control.resolvers.go +++ b/pkg/server/api/console/v1/control.resolvers.go @@ -865,76 +865,6 @@ func (r *mutationResolver) ExportStatementOfApplicabilityPDF(ctx context.Context }, 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 -} - -// 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/data_protection_impact_assessment.resolvers.go b/pkg/server/api/console/v1/data_protection_impact_assessment.resolvers.go index 4505bcd8c..920ad0387 100644 --- a/pkg/server/api/console/v1/data_protection_impact_assessment.resolvers.go +++ b/pkg/server/api/console/v1/data_protection_impact_assessment.resolvers.go @@ -15,7 +15,6 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/server/api/console/v1/dataloader" "go.probo.inc/probo/pkg/server/api/console/v1/schema" @@ -326,78 +325,6 @@ func (r *mutationResolver) ExportTransferImpactAssessmentsPDF(ctx context.Contex }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/document.resolvers.go b/pkg/server/api/console/v1/document.resolvers.go index c87905bf1..a3b1b77f5 100644 --- a/pkg/server/api/console/v1/document.resolvers.go +++ b/pkg/server/api/console/v1/document.resolvers.go @@ -1633,202 +1633,6 @@ func (r *mutationResolver) ExportEmployeeDocumentVersionPDF(ctx context.Context, }, 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 -} - -// 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 -} - // Document returns schema.DocumentResolver implementation. func (r *Resolver) Document() schema.DocumentResolver { return &documentResolver{r} } diff --git a/pkg/server/api/console/v1/evidence.resolvers.go b/pkg/server/api/console/v1/evidence.resolvers.go index ff9c198c9..ad1bec21e 100644 --- a/pkg/server/api/console/v1/evidence.resolvers.go +++ b/pkg/server/api/console/v1/evidence.resolvers.go @@ -8,12 +8,10 @@ package console_v1 import ( "context" "errors" - "fmt" "github.com/vikstrous/dataloadgen" "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/server/api/console/v1/dataloader" "go.probo.inc/probo/pkg/server/api/console/v1/schema" @@ -180,11 +178,6 @@ func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input type }, nil } -// Evidences is the resolver for the evidences field. -func (r *organizationResolver) Evidences(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) { - panic(fmt.Errorf("not implemented: Evidences - evidences")) -} - // Evidence returns schema.EvidenceResolver implementation. func (r *Resolver) Evidence() schema.EvidenceResolver { return &evidenceResolver{r} } diff --git a/pkg/server/api/console/v1/framework.resolvers.go b/pkg/server/api/console/v1/framework.resolvers.go index bd74601ef..df6796bcc 100644 --- a/pkg/server/api/console/v1/framework.resolvers.go +++ b/pkg/server/api/console/v1/framework.resolvers.go @@ -259,36 +259,6 @@ func (r *mutationResolver) ExportFramework(ctx context.Context, input types.Expo }, 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 -} - // Framework returns schema.FrameworkResolver implementation. func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} } diff --git a/pkg/server/api/console/v1/graphql/access_review_campaign.graphql b/pkg/server/api/console/v1/graphql/access_review_campaign.graphql index 56a3a39a0..ba69e97e7 100644 --- a/pkg/server/api/console/v1/graphql/access_review_campaign.graphql +++ b/pkg/server/api/console/v1/graphql/access_review_campaign.graphql @@ -1,21 +1,3 @@ -extend type Organization { - accessSources( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AccessSourceOrder - ): AccessSourceConnection! @goField(forceResolver: true) - - accessReviewCampaigns( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AccessReviewCampaignOrder - ): AccessReviewCampaignConnection! @goField(forceResolver: true) -} - enum AccessReviewCampaignStatus @goModel( model: "go.probo.inc/probo/pkg/coredata.AccessReviewCampaignStatus" diff --git a/pkg/server/api/console/v1/graphql/asset.graphql b/pkg/server/api/console/v1/graphql/asset.graphql index 9fa2cf38f..961030854 100644 --- a/pkg/server/api/console/v1/graphql/asset.graphql +++ b/pkg/server/api/console/v1/graphql/asset.graphql @@ -1,23 +1,3 @@ -extend type Organization { - assets( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AssetOrder - filter: AssetFilter = { snapshotId: null } - ): AssetConnection! @goField(forceResolver: true) - - data( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: DatumOrder - filter: DatumFilter = { snapshotId: null } - ): DatumConnection! @goField(forceResolver: true) -} - enum AssetType @goModel(model: "go.probo.inc/probo/pkg/coredata.AssetType") { PHYSICAL @goEnum(value: "go.probo.inc/probo/pkg/coredata.AssetTypePhysical") VIRTUAL @goEnum(value: "go.probo.inc/probo/pkg/coredata.AssetTypeVirtual") diff --git a/pkg/server/api/console/v1/graphql/audit.graphql b/pkg/server/api/console/v1/graphql/audit.graphql index 7eac1ffc1..00bd0189e 100644 --- a/pkg/server/api/console/v1/graphql/audit.graphql +++ b/pkg/server/api/console/v1/graphql/audit.graphql @@ -1,22 +1,3 @@ -extend type Organization { - audits( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AuditOrder - ): AuditConnection! @goField(forceResolver: true) - - findings( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: FindingOrder - filter: FindingFilter = { snapshotId: null } - ): FindingConnection @goField(forceResolver: true) -} - enum AuditState @goModel(model: "go.probo.inc/probo/pkg/coredata.AuditState") { NOT_STARTED @goEnum(value: "go.probo.inc/probo/pkg/coredata.AuditStateNotStarted") diff --git a/pkg/server/api/console/v1/graphql/audit_log.graphql b/pkg/server/api/console/v1/graphql/audit_log.graphql index d2751a92c..9f84d0ce5 100644 --- a/pkg/server/api/console/v1/graphql/audit_log.graphql +++ b/pkg/server/api/console/v1/graphql/audit_log.graphql @@ -1,14 +1,3 @@ -extend type Organization { - auditLogEntries( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: AuditLogEntryOrder - filter: AuditLogEntryFilter - ): AuditLogEntryConnection! @goField(forceResolver: true) -} - enum AuditLogActorType @goModel( model: "go.probo.inc/probo/pkg/coredata.AuditLogActorType" diff --git a/pkg/server/api/console/v1/graphql/base.graphql b/pkg/server/api/console/v1/graphql/base.graphql index dd6c8d75f..680fcfd29 100644 --- a/pkg/server/api/console/v1/graphql/base.graphql +++ b/pkg/server/api/console/v1/graphql/base.graphql @@ -311,35 +311,28 @@ type Query { type Viewer { id: ID! -} -type Organization implements Node { - id: ID! - name: String! - logoUrl: String @goField(forceResolver: true) - horizontalLogoUrl: String @goField(forceResolver: true) - - description: String - websiteUrl: String - email: String - headquarterAddress: String - context: OrganizationContext @goField(forceResolver: true) - - profiles( + signableDocuments( + organizationId: ID! first: Int after: CursorKey last: Int before: CursorKey - orderBy: ProfileOrder - filter: ProfileFilter - ): ProfileConnection! @goField(forceResolver: true) + orderBy: DocumentOrder + ): EmployeeDocumentConnection! @goField(forceResolver: true) - measureCategories: [String!]! @goField(forceResolver: true) + signableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true) - createdAt: Datetime! - updatedAt: Datetime! + approvableDocuments( + organizationId: ID! + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: DocumentOrder + ): EmployeeDocumentConnection! @goField(forceResolver: true) - permission(action: String!): Boolean! @goField(forceResolver: true) + approvableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true) } type Mutation { diff --git a/pkg/server/api/console/v1/graphql/connector.graphql b/pkg/server/api/console/v1/graphql/connector.graphql index 2c7731b5f..f0dc612f8 100644 --- a/pkg/server/api/console/v1/graphql/connector.graphql +++ b/pkg/server/api/console/v1/graphql/connector.graphql @@ -1,15 +1,3 @@ -extend type Organization { - slackConnections( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): SlackConnectionConnection! @goField(forceResolver: true) - slackOAuth2Scopes: [String!]! @goField(forceResolver: true) - connectors(filter: ConnectorFilter): [Connector!]! @goField(forceResolver: true) - connectorProviderInfos: [ConnectorProviderInfo!]! @goField(forceResolver: true) -} - enum ConnectorProvider @goModel(model: "go.probo.inc/probo/pkg/coredata.ConnectorProvider") { SLACK @goEnum(value: "go.probo.inc/probo/pkg/coredata.ConnectorProviderSlack") diff --git a/pkg/server/api/console/v1/graphql/control.graphql b/pkg/server/api/console/v1/graphql/control.graphql index f5b1ad5ec..607acb09a 100644 --- a/pkg/server/api/console/v1/graphql/control.graphql +++ b/pkg/server/api/console/v1/graphql/control.graphql @@ -1,23 +1,3 @@ -extend type Organization { - controls( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: ControlOrder - filter: ControlFilter - ): ControlConnection! @goField(forceResolver: true) - - statementsOfApplicability( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: StatementOfApplicabilityOrder - filter: StatementOfApplicabilityFilter = { snapshotId: null } - ): StatementOfApplicabilityConnection! @goField(forceResolver: true) -} - enum ControlImplementationState @goModel( model: "go.probo.inc/probo/pkg/coredata.ControlImplementationState" diff --git a/pkg/server/api/console/v1/graphql/data_protection_impact_assessment.graphql b/pkg/server/api/console/v1/graphql/data_protection_impact_assessment.graphql index 1ccd81f8f..86c1fdc6b 100644 --- a/pkg/server/api/console/v1/graphql/data_protection_impact_assessment.graphql +++ b/pkg/server/api/console/v1/graphql/data_protection_impact_assessment.graphql @@ -1,23 +1,3 @@ -extend type Organization { - dataProtectionImpactAssessments( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: DataProtectionImpactAssessmentOrder - filter: DataProtectionImpactAssessmentFilter = { snapshotId: null } - ): DataProtectionImpactAssessmentConnection! @goField(forceResolver: true) - - transferImpactAssessments( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: TransferImpactAssessmentOrder - filter: TransferImpactAssessmentFilter = { snapshotId: null } - ): TransferImpactAssessmentConnection! @goField(forceResolver: true) -} - enum DataProtectionImpactAssessmentResidualRisk @goModel( model: "go.probo.inc/probo/pkg/coredata.DataProtectionImpactAssessmentResidualRisk" diff --git a/pkg/server/api/console/v1/graphql/document.graphql b/pkg/server/api/console/v1/graphql/document.graphql index 4339f2d86..557c894cf 100644 --- a/pkg/server/api/console/v1/graphql/document.graphql +++ b/pkg/server/api/console/v1/graphql/document.graphql @@ -1,38 +1,3 @@ -extend type Organization { - documents( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: DocumentOrder - filter: DocumentFilter - ): DocumentConnection! @goField(forceResolver: true) -} - -extend type Viewer { - signableDocuments( - organizationId: ID! - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: DocumentOrder - ): EmployeeDocumentConnection! @goField(forceResolver: true) - - signableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true) - - approvableDocuments( - organizationId: ID! - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: DocumentOrder - ): EmployeeDocumentConnection! @goField(forceResolver: true) - - approvableDocument(id: ID!): EmployeeDocument @goField(forceResolver: true) -} - enum DocumentVersionStatus @goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatus") { DRAFT diff --git a/pkg/server/api/console/v1/graphql/evidence.graphql b/pkg/server/api/console/v1/graphql/evidence.graphql index b5fc2c505..c99361668 100644 --- a/pkg/server/api/console/v1/graphql/evidence.graphql +++ b/pkg/server/api/console/v1/graphql/evidence.graphql @@ -1,13 +1,3 @@ -extend type Organization { - evidences( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: EvidenceOrder - ): EvidenceConnection! @goField(forceResolver: true) -} - enum EvidenceState @goModel(model: "go.probo.inc/probo/pkg/coredata.EvidenceState") { FULFILLED diff --git a/pkg/server/api/console/v1/graphql/framework.graphql b/pkg/server/api/console/v1/graphql/framework.graphql index f07382e7f..68d0a8672 100644 --- a/pkg/server/api/console/v1/graphql/framework.graphql +++ b/pkg/server/api/console/v1/graphql/framework.graphql @@ -1,13 +1,3 @@ -extend type Organization { - frameworks( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: FrameworkOrder - ): FrameworkConnection! @goField(forceResolver: true) -} - enum FrameworkOrderField @goModel(model: "go.probo.inc/probo/pkg/coredata.FrameworkOrderField") { CREATED_AT diff --git a/pkg/server/api/console/v1/graphql/measure.graphql b/pkg/server/api/console/v1/graphql/measure.graphql index 71072ac33..988b2a889 100644 --- a/pkg/server/api/console/v1/graphql/measure.graphql +++ b/pkg/server/api/console/v1/graphql/measure.graphql @@ -1,14 +1,3 @@ -extend type Organization { - measures( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: MeasureOrder - filter: MeasureFilter - ): MeasureConnection! @goField(forceResolver: true) -} - enum MeasureState @goModel(model: "go.probo.inc/probo/pkg/coredata.MeasureState") { NOT_STARTED diff --git a/pkg/server/api/console/v1/graphql/meeting.graphql b/pkg/server/api/console/v1/graphql/meeting.graphql index 417f2113a..dbcb15fc2 100644 --- a/pkg/server/api/console/v1/graphql/meeting.graphql +++ b/pkg/server/api/console/v1/graphql/meeting.graphql @@ -1,13 +1,3 @@ -extend type Organization { - meetings( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: MeetingOrder - ): MeetingConnection! @goField(forceResolver: true) -} - enum MeetingOrderField @goModel(model: "go.probo.inc/probo/pkg/coredata.MeetingOrderField") { DATE @goEnum(value: "go.probo.inc/probo/pkg/coredata.MeetingOrderFieldDate") diff --git a/pkg/server/api/console/v1/graphql/obligation.graphql b/pkg/server/api/console/v1/graphql/obligation.graphql index 1a42052b6..5546db8eb 100644 --- a/pkg/server/api/console/v1/graphql/obligation.graphql +++ b/pkg/server/api/console/v1/graphql/obligation.graphql @@ -1,14 +1,3 @@ -extend type Organization { - obligations( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: ObligationOrder - filter: ObligationFilter = { snapshotId: null } - ): ObligationConnection! @goField(forceResolver: true) -} - enum ObligationStatus @goModel(model: "go.probo.inc/probo/pkg/coredata.ObligationStatus") { NON_COMPLIANT diff --git a/pkg/server/api/console/v1/graphql/organization.graphql b/pkg/server/api/console/v1/graphql/organization.graphql index bd0e345cb..b8150e14b 100644 --- a/pkg/server/api/console/v1/graphql/organization.graphql +++ b/pkg/server/api/console/v1/graphql/organization.graphql @@ -81,3 +81,258 @@ input UpdateOrganizationContextInput { type UpdateOrganizationContextPayload { context: OrganizationContext! } + +type Organization implements Node { + id: ID! + name: String! + logoUrl: String @goField(forceResolver: true) + horizontalLogoUrl: String @goField(forceResolver: true) + + description: String + websiteUrl: String + email: String + headquarterAddress: String + context: OrganizationContext @goField(forceResolver: true) + + profiles( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ProfileOrder + filter: ProfileFilter + ): ProfileConnection! @goField(forceResolver: true) + + measureCategories: [String!]! @goField(forceResolver: true) + + accessSources( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AccessSourceOrder + ): AccessSourceConnection! @goField(forceResolver: true) + + accessReviewCampaigns( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AccessReviewCampaignOrder + ): AccessReviewCampaignConnection! @goField(forceResolver: true) + + assets( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AssetOrder + filter: AssetFilter = { snapshotId: null } + ): AssetConnection! @goField(forceResolver: true) + + data( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: DatumOrder + filter: DatumFilter = { snapshotId: null } + ): DatumConnection! @goField(forceResolver: true) + + audits( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AuditOrder + ): AuditConnection! @goField(forceResolver: true) + + findings( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: FindingOrder + filter: FindingFilter = { snapshotId: null } + ): FindingConnection @goField(forceResolver: true) + + auditLogEntries( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: AuditLogEntryOrder + filter: AuditLogEntryFilter + ): AuditLogEntryConnection! @goField(forceResolver: true) + + slackConnections( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): SlackConnectionConnection! @goField(forceResolver: true) + slackOAuth2Scopes: [String!]! @goField(forceResolver: true) + connectors(filter: ConnectorFilter): [Connector!]! @goField(forceResolver: true) + connectorProviderInfos: [ConnectorProviderInfo!]! @goField(forceResolver: true) + + controls( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ControlOrder + filter: ControlFilter + ): ControlConnection! @goField(forceResolver: true) + + statementsOfApplicability( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: StatementOfApplicabilityOrder + filter: StatementOfApplicabilityFilter = { snapshotId: null } + ): StatementOfApplicabilityConnection! @goField(forceResolver: true) + + dataProtectionImpactAssessments( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: DataProtectionImpactAssessmentOrder + filter: DataProtectionImpactAssessmentFilter = { snapshotId: null } + ): DataProtectionImpactAssessmentConnection! @goField(forceResolver: true) + + transferImpactAssessments( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: TransferImpactAssessmentOrder + filter: TransferImpactAssessmentFilter = { snapshotId: null } + ): TransferImpactAssessmentConnection! @goField(forceResolver: true) + + documents( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: DocumentOrder + filter: DocumentFilter + ): DocumentConnection! @goField(forceResolver: true) + + evidences( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: EvidenceOrder + ): EvidenceConnection! @goField(forceResolver: true) + + frameworks( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: FrameworkOrder + ): FrameworkConnection! @goField(forceResolver: true) + + measures( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: MeasureOrder + filter: MeasureFilter + ): MeasureConnection! @goField(forceResolver: true) + + meetings( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: MeetingOrder + ): MeetingConnection! @goField(forceResolver: true) + + obligations( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ObligationOrder + filter: ObligationFilter = { snapshotId: null } + ): ObligationConnection! @goField(forceResolver: true) + + processingActivities( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: ProcessingActivityOrder + filter: ProcessingActivityFilter = { snapshotId: null } + ): ProcessingActivityConnection! @goField(forceResolver: true) + + rightsRequests( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: RightsRequestOrder + ): RightsRequestConnection! @goField(forceResolver: true) + + risks( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: RiskOrder + filter: RiskFilter = { snapshotId: null } + ): RiskConnection! @goField(forceResolver: true) + + snapshots( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: SnapshotOrder + ): SnapshotConnection! @goField(forceResolver: true) + + tasks( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: TaskOrder + ): TaskConnection! @goField(forceResolver: true) + + trustCenter: TrustCenter @goField(forceResolver: true) + customDomain: CustomDomain @goField(forceResolver: true) + trustCenterFiles( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: TrustCenterFileOrder + ): TrustCenterFileConnection! @goField(forceResolver: true) + + vendors( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: VendorOrder + filter: VendorFilter = { snapshotId: null } + ): VendorConnection! @goField(forceResolver: true) + + webhookSubscriptions( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: WebhookSubscriptionOrder + ): WebhookSubscriptionConnection! @goField(forceResolver: true) + + createdAt: Datetime! + updatedAt: Datetime! + + permission(action: String!): Boolean! @goField(forceResolver: true) +} diff --git a/pkg/server/api/console/v1/graphql/processing_activity.graphql b/pkg/server/api/console/v1/graphql/processing_activity.graphql index efbfdd799..6b72edfed 100644 --- a/pkg/server/api/console/v1/graphql/processing_activity.graphql +++ b/pkg/server/api/console/v1/graphql/processing_activity.graphql @@ -1,14 +1,3 @@ -extend type Organization { - processingActivities( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: ProcessingActivityOrder - filter: ProcessingActivityFilter = { snapshotId: null } - ): ProcessingActivityConnection! @goField(forceResolver: true) -} - enum ProcessingActivitySpecialOrCriminalDatum @goModel( model: "go.probo.inc/probo/pkg/coredata.ProcessingActivitySpecialOrCriminalDatum" diff --git a/pkg/server/api/console/v1/graphql/rights_request.graphql b/pkg/server/api/console/v1/graphql/rights_request.graphql index 0e3ba7eca..5e2907167 100644 --- a/pkg/server/api/console/v1/graphql/rights_request.graphql +++ b/pkg/server/api/console/v1/graphql/rights_request.graphql @@ -1,13 +1,3 @@ -extend type Organization { - rightsRequests( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: RightsRequestOrder - ): RightsRequestConnection! @goField(forceResolver: true) -} - enum RightsRequestType @goModel(model: "go.probo.inc/probo/pkg/coredata.RightsRequestType") { ACCESS diff --git a/pkg/server/api/console/v1/graphql/risk.graphql b/pkg/server/api/console/v1/graphql/risk.graphql index 4a04ff6fc..3c7006640 100644 --- a/pkg/server/api/console/v1/graphql/risk.graphql +++ b/pkg/server/api/console/v1/graphql/risk.graphql @@ -1,14 +1,3 @@ -extend type Organization { - risks( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: RiskOrder - filter: RiskFilter = { snapshotId: null } - ): RiskConnection! @goField(forceResolver: true) -} - enum RiskTreatment @goModel(model: "go.probo.inc/probo/pkg/coredata.RiskTreatment") { MITIGATED diff --git a/pkg/server/api/console/v1/graphql/snapshot.graphql b/pkg/server/api/console/v1/graphql/snapshot.graphql index b7122f813..50bb8ef31 100644 --- a/pkg/server/api/console/v1/graphql/snapshot.graphql +++ b/pkg/server/api/console/v1/graphql/snapshot.graphql @@ -1,13 +1,3 @@ -extend type Organization { - snapshots( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: SnapshotOrder - ): SnapshotConnection! @goField(forceResolver: true) -} - enum SnapshotsType @goModel(model: "go.probo.inc/probo/pkg/coredata.SnapshotsType") { RISKS @goEnum(value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeRisks") diff --git a/pkg/server/api/console/v1/graphql/task.graphql b/pkg/server/api/console/v1/graphql/task.graphql index 71d2ff40e..80d41524d 100644 --- a/pkg/server/api/console/v1/graphql/task.graphql +++ b/pkg/server/api/console/v1/graphql/task.graphql @@ -1,13 +1,3 @@ -extend type Organization { - tasks( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: TaskOrder - ): TaskConnection! @goField(forceResolver: true) -} - enum TaskState @goModel(model: "go.probo.inc/probo/pkg/coredata.TaskState") { TODO @goEnum(value: "go.probo.inc/probo/pkg/coredata.TaskStateTodo") IN_PROGRESS @goEnum(value: "go.probo.inc/probo/pkg/coredata.TaskStateInProgress") diff --git a/pkg/server/api/console/v1/graphql/trust_center.graphql b/pkg/server/api/console/v1/graphql/trust_center.graphql index f03dc3565..510b97955 100644 --- a/pkg/server/api/console/v1/graphql/trust_center.graphql +++ b/pkg/server/api/console/v1/graphql/trust_center.graphql @@ -1,15 +1,3 @@ -extend type Organization { - trustCenter: TrustCenter @goField(forceResolver: true) - customDomain: CustomDomain @goField(forceResolver: true) - trustCenterFiles( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: TrustCenterFileOrder - ): TrustCenterFileConnection! @goField(forceResolver: true) -} - enum TrustCenterVisibility @goModel(model: "go.probo.inc/probo/pkg/coredata.TrustCenterVisibility") { NONE diff --git a/pkg/server/api/console/v1/graphql/vendor.graphql b/pkg/server/api/console/v1/graphql/vendor.graphql index 064d10987..a1ab02f93 100644 --- a/pkg/server/api/console/v1/graphql/vendor.graphql +++ b/pkg/server/api/console/v1/graphql/vendor.graphql @@ -1,14 +1,3 @@ -extend type Organization { - vendors( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: VendorOrder - filter: VendorFilter = { snapshotId: null } - ): VendorConnection! @goField(forceResolver: true) -} - enum VendorCategory @goModel(model: "go.probo.inc/probo/pkg/coredata.VendorCategory") { ANALYTICS diff --git a/pkg/server/api/console/v1/graphql/webhook.graphql b/pkg/server/api/console/v1/graphql/webhook.graphql index 045c70529..0f988cd14 100644 --- a/pkg/server/api/console/v1/graphql/webhook.graphql +++ b/pkg/server/api/console/v1/graphql/webhook.graphql @@ -1,13 +1,3 @@ -extend type Organization { - webhookSubscriptions( - first: Int - after: CursorKey - last: Int - before: CursorKey - orderBy: WebhookSubscriptionOrder - ): WebhookSubscriptionConnection! @goField(forceResolver: true) -} - enum WebhookEventType @goModel(model: "go.probo.inc/probo/pkg/coredata.WebhookEventType") { MEETING_CREATED diff --git a/pkg/server/api/console/v1/measure.resolvers.go b/pkg/server/api/console/v1/measure.resolvers.go index d85e3062e..9c912f6ca 100644 --- a/pkg/server/api/console/v1/measure.resolvers.go +++ b/pkg/server/api/console/v1/measure.resolvers.go @@ -386,41 +386,6 @@ func (r *mutationResolver) DeleteMeasureDocumentMapping(ctx context.Context, inp }, 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 -} - // Measure returns schema.MeasureResolver implementation. func (r *Resolver) Measure() schema.MeasureResolver { return &measureResolver{r} } diff --git a/pkg/server/api/console/v1/meeting.resolvers.go b/pkg/server/api/console/v1/meeting.resolvers.go index 6de2f789d..8a6d96d4a 100644 --- a/pkg/server/api/console/v1/meeting.resolvers.go +++ b/pkg/server/api/console/v1/meeting.resolvers.go @@ -14,7 +14,6 @@ import ( "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/dataloader" "go.probo.inc/probo/pkg/server/api/console/v1/schema" @@ -185,36 +184,6 @@ func (r *mutationResolver) DeleteMeeting(ctx context.Context, input types.Delete }, 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 -} - // Meeting returns schema.MeetingResolver implementation. func (r *Resolver) Meeting() schema.MeetingResolver { return &meetingResolver{r} } diff --git a/pkg/server/api/console/v1/obligation.resolvers.go b/pkg/server/api/console/v1/obligation.resolvers.go index 2f6614103..e2d0c1ac1 100644 --- a/pkg/server/api/console/v1/obligation.resolvers.go +++ b/pkg/server/api/console/v1/obligation.resolvers.go @@ -13,7 +13,6 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "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/dataloader" "go.probo.inc/probo/pkg/server/api/console/v1/schema" @@ -199,42 +198,6 @@ func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *type return 0, gqlutils.Internal(ctx) } -// 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 -} - // Obligation returns schema.ObligationResolver implementation. func (r *Resolver) Obligation() schema.ObligationResolver { return &obligationResolver{r} } diff --git a/pkg/server/api/console/v1/organization.resolvers.go b/pkg/server/api/console/v1/organization.resolvers.go index 99f35105f..462d2941c 100644 --- a/pkg/server/api/console/v1/organization.resolvers.go +++ b/pkg/server/api/console/v1/organization.resolvers.go @@ -8,14 +8,1094 @@ package console_v1 import ( "context" "fmt" + "time" "go.gearno.de/kit/log" + "go.probo.inc/probo/pkg/accessreview/drivers" + "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" ) +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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) { + 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// Evidences is the resolver for the evidences field. +func (r *organizationResolver) Evidences(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) { + panic(fmt.Errorf("not implemented: Evidences - evidences")) +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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) @@ -49,6 +1129,9 @@ func (r *profileConnectionResolver) TotalCount(ctx context.Context, obj *types.P 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} } @@ -57,5 +1140,6 @@ func (r *Resolver) ProfileConnection() schema.ProfileConnectionResolver { return &profileConnectionResolver{r} } +type organizationResolver struct{ *Resolver } type profileResolver struct{ *Resolver } type profileConnectionResolver struct{ *Resolver } diff --git a/pkg/server/api/console/v1/processing_activity.resolvers.go b/pkg/server/api/console/v1/processing_activity.resolvers.go index fc81c40fd..e0f9902c0 100644 --- a/pkg/server/api/console/v1/processing_activity.resolvers.go +++ b/pkg/server/api/console/v1/processing_activity.resolvers.go @@ -155,42 +155,6 @@ func (r *mutationResolver) ExportProcessingActivitiesPDF(ctx context.Context, in }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/rights_request.resolvers.go b/pkg/server/api/console/v1/rights_request.resolvers.go index 119d73f34..9761a1b8f 100644 --- a/pkg/server/api/console/v1/rights_request.resolvers.go +++ b/pkg/server/api/console/v1/rights_request.resolvers.go @@ -12,7 +12,6 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "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" @@ -105,37 +104,6 @@ func (r *mutationResolver) DeleteRightsRequest(ctx context.Context, input types. }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/risk.resolvers.go b/pkg/server/api/console/v1/risk.resolvers.go index d8675407d..24ec5c69d 100644 --- a/pkg/server/api/console/v1/risk.resolvers.go +++ b/pkg/server/api/console/v1/risk.resolvers.go @@ -239,41 +239,6 @@ func (r *mutationResolver) DeleteRiskObligationMapping(ctx context.Context, inpu }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/snapshot.resolvers.go b/pkg/server/api/console/v1/snapshot.resolvers.go index 1115a12e7..05fbac01e 100644 --- a/pkg/server/api/console/v1/snapshot.resolvers.go +++ b/pkg/server/api/console/v1/snapshot.resolvers.go @@ -64,36 +64,6 @@ func (r *mutationResolver) DeleteSnapshot(ctx context.Context, input types.Delet }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/task.resolvers.go b/pkg/server/api/console/v1/task.resolvers.go index c9f59c53e..7f3fe2e08 100644 --- a/pkg/server/api/console/v1/task.resolvers.go +++ b/pkg/server/api/console/v1/task.resolvers.go @@ -115,36 +115,6 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTas }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/trust_center.resolvers.go b/pkg/server/api/console/v1/trust_center.resolvers.go index 4eb3ec8dc..57509f59a 100644 --- a/pkg/server/api/console/v1/trust_center.resolvers.go +++ b/pkg/server/api/console/v1/trust_center.resolvers.go @@ -675,83 +675,6 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D }, 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 -} - -// 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/vendor.resolvers.go b/pkg/server/api/console/v1/vendor.resolvers.go index ae60f5fc0..329ac9d6e 100644 --- a/pkg/server/api/console/v1/vendor.resolvers.go +++ b/pkg/server/api/console/v1/vendor.resolvers.go @@ -558,41 +558,6 @@ func (r *mutationResolver) AssessVendor(ctx context.Context, input types.AssessV }, 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 -} - // 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 { diff --git a/pkg/server/api/console/v1/webhook.resolvers.go b/pkg/server/api/console/v1/webhook.resolvers.go index 93349687e..32fd3ab0e 100644 --- a/pkg/server/api/console/v1/webhook.resolvers.go +++ b/pkg/server/api/console/v1/webhook.resolvers.go @@ -99,36 +99,6 @@ func (r *mutationResolver) DeleteWebhookSubscription(ctx context.Context, input }, 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 -} - // 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 { diff --git a/pkg/server/api/trust/v1/base.resolvers.go b/pkg/server/api/trust/v1/base.resolvers.go index 329cc0d33..58053abb6 100644 --- a/pkg/server/api/trust/v1/base.resolvers.go +++ b/pkg/server/api/trust/v1/base.resolvers.go @@ -16,7 +16,6 @@ import ( "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/saferedirect" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/compliancepage" @@ -350,164 +349,6 @@ func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProvide return result, nil } -// LogoFileURL is the resolver for the logoFileUrl field. -func (r *trustCenterResolver) LogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - return trustService.TrustCenters.GenerateLogoURL(ctx, obj.ID, 1*time.Hour) -} - -// DarkLogoFileURL is the resolver for the darkLogoFileUrl field. -func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - return trustService.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour) -} - -// Organization is the resolver for the organization field. -func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) { - return obj.Organization, nil -} - -// Documents is the resolver for the documents field. -func (r *trustCenterResolver) Documents(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.DocumentConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{ - Field: coredata.DocumentOrderFieldTitle, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - documentPage, err := trustService.Documents.ListForOrganizationId(ctx, obj.Organization.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list public documents", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewDocumentConnection(documentPage), nil -} - -// Audits is the resolver for the audits field. -func (r *trustCenterResolver) Audits(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.AuditConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.AuditOrderField]{ - Field: coredata.AuditOrderFieldValidFrom, - Direction: page.OrderDirectionDesc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - auditPage, err := trustService.Audits.ListForOrganizationId(ctx, obj.Organization.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list public audits", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewAuditConnection(auditPage), nil -} - -// Subprocessors is the resolver for the subprocessors field. -func (r *trustCenterResolver) Subprocessors(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SubprocessorConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.VendorOrderField]{ - Field: coredata.VendorOrderFieldName, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - vendorPage, err := trustService.Vendors.ListForOrganizationId(ctx, obj.Organization.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list subprocessors", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewSubprocessorConnection(vendorPage, r, obj.ID), 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) (*types.TrustCenterReferenceConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.TrustCenterReferenceOrderField]{ - Field: coredata.TrustCenterReferenceOrderFieldRank, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - referencePage, err := trustService.TrustCenterReferences.ListForTrustCenterID(ctx, obj.ID, cursor) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list public trust center references", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewTrustCenterReferenceConnection(referencePage), nil -} - -// TrustCenterFiles is the resolver for the trustCenterFiles field. -func (r *trustCenterResolver) TrustCenterFiles(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TrustCenterFileConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.TrustCenterFileOrderField]{ - Field: coredata.TrustCenterFileOrderFieldName, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - filter := coredata.NewTrustCenterFileFilter( - coredata.WithTrustCenterFileVisibilities( - coredata.TrustCenterVisibilityPublic, - coredata.TrustCenterVisibilityPrivate, - ), - ) - trustCenterFilePage, err := trustService.TrustCenterFiles.ListForOrganizationId(ctx, obj.Organization.ID, cursor, filter) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot list public trust center files", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return types.NewTrustCenterFileConnection(trustCenterFilePage), 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) (*types.ComplianceFrameworkConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{ - Field: coredata.ComplianceFrameworkOrderFieldRank, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - cfPage, err := trustService.ComplianceFrameworks.ListByTrustCenterID(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(cfPage), 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) (*types.ComplianceExternalURLConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - pageOrderBy := page.OrderBy[coredata.ComplianceExternalURLOrderField]{ - Field: coredata.ComplianceExternalURLOrderFieldRank, - Direction: page.OrderDirectionAsc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - result, err := trustService.ComplianceExternalURLs.ListForTrustCenterID(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 -} - // Mutation returns schema.MutationResolver implementation. func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} } @@ -517,10 +358,6 @@ func (r *Resolver) Organization() schema.OrganizationResolver { return &organiza // Query returns schema.QueryResolver implementation. func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} } -// TrustCenter returns schema.TrustCenterResolver implementation. -func (r *Resolver) TrustCenter() schema.TrustCenterResolver { return &trustCenterResolver{r} } - type mutationResolver struct{ *Resolver } type organizationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } -type trustCenterResolver struct{ *Resolver } diff --git a/pkg/server/api/trust/v1/graphql/base.graphql b/pkg/server/api/trust/v1/graphql/base.graphql index 3568df9ca..18294645e 100644 --- a/pkg/server/api/trust/v1/graphql/base.graphql +++ b/pkg/server/api/trust/v1/graphql/base.graphql @@ -315,65 +315,6 @@ type Query { @session(required: OPTIONAL) } -type TrustCenter implements Node { - id: ID! - active: Boolean! - slug: String! - logoFileUrl: String @goField(forceResolver: true) - darkLogoFileUrl: String @goField(forceResolver: true) - - organization: Organization! @goField(forceResolver: true) - - documents( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): DocumentConnection! @goField(forceResolver: true) - - audits( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): AuditConnection! @goField(forceResolver: true) - - subprocessors( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): SubprocessorConnection! @goField(forceResolver: true) - - references( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): TrustCenterReferenceConnection! @goField(forceResolver: true) - - trustCenterFiles( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): TrustCenterFileConnection! @goField(forceResolver: true) - - complianceFrameworks( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): ComplianceFrameworkConnection! @goField(forceResolver: true) - - externalUrls( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): ComplianceExternalURLConnection! @goField(forceResolver: true) -} - type Mutation { sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload @session(required: OPTIONAL) diff --git a/pkg/server/api/trust/v1/graphql/mailing_list.graphql b/pkg/server/api/trust/v1/graphql/mailing_list.graphql index ed98b0288..8b38efe4a 100644 --- a/pkg/server/api/trust/v1/graphql/mailing_list.graphql +++ b/pkg/server/api/trust/v1/graphql/mailing_list.graphql @@ -1,14 +1,3 @@ -extend type TrustCenter { - viewerSubscription: MailingListSubscriber @goField(forceResolver: true) - - updates( - first: Int - after: CursorKey - last: Int - before: CursorKey - ): MailingListUpdateConnection! @goField(forceResolver: true) -} - type MailingListUpdate implements Node { id: ID! title: String! diff --git a/pkg/server/api/trust/v1/graphql/nda.graphql b/pkg/server/api/trust/v1/graphql/nda.graphql index 064615569..0425fa62d 100644 --- a/pkg/server/api/trust/v1/graphql/nda.graphql +++ b/pkg/server/api/trust/v1/graphql/nda.graphql @@ -1,7 +1,3 @@ -extend type TrustCenter { - nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true) -} - type NonDisclosureAgreement { fileName: String! fileUrl: String! @goField(forceResolver: true) diff --git a/pkg/server/api/trust/v1/graphql/trust_center.graphql b/pkg/server/api/trust/v1/graphql/trust_center.graphql index d68bb21dd..01443f1b1 100644 --- a/pkg/server/api/trust/v1/graphql/trust_center.graphql +++ b/pkg/server/api/trust/v1/graphql/trust_center.graphql @@ -1,3 +1,73 @@ +type TrustCenter implements Node { + id: ID! + active: Boolean! + slug: String! + logoFileUrl: String @goField(forceResolver: true) + darkLogoFileUrl: String @goField(forceResolver: true) + + nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true) + + viewerSubscription: MailingListSubscriber @goField(forceResolver: true) + + organization: Organization! @goField(forceResolver: true) + + documents( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): DocumentConnection! @goField(forceResolver: true) + + audits( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): AuditConnection! @goField(forceResolver: true) + + subprocessors( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): SubprocessorConnection! @goField(forceResolver: true) + + references( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): TrustCenterReferenceConnection! @goField(forceResolver: true) + + trustCenterFiles( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): TrustCenterFileConnection! @goField(forceResolver: true) + + complianceFrameworks( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): ComplianceFrameworkConnection! @goField(forceResolver: true) + + externalUrls( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): ComplianceExternalURLConnection! @goField(forceResolver: true) + + updates( + first: Int + after: CursorKey + last: Int + before: CursorKey + ): MailingListUpdateConnection! @goField(forceResolver: true) +} + enum DocumentType @goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentType") { OTHER @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentTypeOther") diff --git a/pkg/server/api/trust/v1/mailing_list.resolvers.go b/pkg/server/api/trust/v1/mailing_list.resolvers.go index c566873e3..383ac003f 100644 --- a/pkg/server/api/trust/v1/mailing_list.resolvers.go +++ b/pkg/server/api/trust/v1/mailing_list.resolvers.go @@ -10,9 +10,7 @@ import ( "errors" "go.gearno.de/kit/log" - "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/mailman" - "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/compliancepage" "go.probo.inc/probo/pkg/server/api/trust/v1/types" @@ -81,57 +79,3 @@ func (r *mutationResolver) UnsubscribeFromMailingList(ctx context.Context) (*typ return &types.UnsubscribeFromMailingListPayload{DeletedMailingListSubscriberID: &subscriber.ID}, nil } - -// ViewerSubscription is the resolver for the viewerSubscription field. -func (r *trustCenterResolver) ViewerSubscription(ctx context.Context, obj *types.TrustCenter) (*types.MailingListSubscriber, error) { - trustCenter := compliancepage.CompliancePageFromContext(ctx) - if trustCenter.MailingListID == nil { - return nil, nil - } - - identity := authn.IdentityFromContext(ctx) - if identity == nil { - return nil, nil - } - - subscriber, err := r.mailman.GetSubscriber(ctx, *trustCenter.MailingListID, identity.EmailAddress) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot get mailing list subscription", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - if subscriber == nil { - return nil, nil - } - - return types.NewMailingListSubscriber(subscriber), nil -} - -// Updates is the resolver for the updates field. -func (r *trustCenterResolver) Updates(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) { - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - tc, err := trustService.TrustCenters.Get(ctx, obj.ID) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot load trust center", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - if tc.MailingListID == nil { - return &types.MailingListUpdateConnection{Edges: []*types.MailingListUpdateEdge{}, PageInfo: &types.PageInfo{}}, nil - } - - pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{ - Field: coredata.MailingListUpdateOrderFieldUpdatedAt, - Direction: page.OrderDirectionDesc, - } - cursor := types.NewCursor(first, after, last, before, pageOrderBy) - - result, err := r.mailman.ListSentMailingListUpdates(ctx, *tc.MailingListID, 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), nil -} diff --git a/pkg/server/api/trust/v1/nda.resolvers.go b/pkg/server/api/trust/v1/nda.resolvers.go index d61863dc4..b1202cafe 100644 --- a/pkg/server/api/trust/v1/nda.resolvers.go +++ b/pkg/server/api/trust/v1/nda.resolvers.go @@ -137,27 +137,6 @@ func (r *nonDisclosureAgreementResolver) ViewerSignature(ctx context.Context, ob return types.NewElectronicSignature(sig), nil } -// NonDisclosureAgreement is the resolver for the nonDisclosureAgreement field. -func (r *trustCenterResolver) NonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (*types.NonDisclosureAgreement, error) { - trustCenter := compliancepage.CompliancePageFromContext(ctx) - if trustCenter.NonDisclosureAgreementFileID == nil { - return nil, nil - } - - trustService := r.TrustService(ctx, obj.ID.TenantID()) - - file, err := trustService.TrustCenters.GetNDAFile(ctx, obj.ID) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot load NDA file", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - if file == nil { - return nil, nil - } - - return types.NewNonDisclosureAgreement(file), nil -} - // NonDisclosureAgreement returns schema.NonDisclosureAgreementResolver implementation. func (r *Resolver) NonDisclosureAgreement() schema.NonDisclosureAgreementResolver { return &nonDisclosureAgreementResolver{r} diff --git a/pkg/server/api/trust/v1/trust_center.resolvers.go b/pkg/server/api/trust/v1/trust_center.resolvers.go index 455685e36..e68590901 100644 --- a/pkg/server/api/trust/v1/trust_center.resolvers.go +++ b/pkg/server/api/trust/v1/trust_center.resolvers.go @@ -15,6 +15,7 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" + "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/compliancepage" "go.probo.inc/probo/pkg/server/api/trust/v1/schema" @@ -609,6 +610,239 @@ func (r *subprocessorConnectionResolver) TotalCount(ctx context.Context, obj *ty 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) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + return trustService.TrustCenters.GenerateLogoURL(ctx, obj.ID, 1*time.Hour) +} + +// DarkLogoFileURL is the resolver for the darkLogoFileUrl field. +func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + return trustService.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour) +} + +// NonDisclosureAgreement is the resolver for the nonDisclosureAgreement field. +func (r *trustCenterResolver) NonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (*types.NonDisclosureAgreement, error) { + trustCenter := compliancepage.CompliancePageFromContext(ctx) + if trustCenter.NonDisclosureAgreementFileID == nil { + return nil, nil + } + + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + file, err := trustService.TrustCenters.GetNDAFile(ctx, obj.ID) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot load NDA file", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + if file == nil { + return nil, nil + } + + return types.NewNonDisclosureAgreement(file), nil +} + +// ViewerSubscription is the resolver for the viewerSubscription field. +func (r *trustCenterResolver) ViewerSubscription(ctx context.Context, obj *types.TrustCenter) (*types.MailingListSubscriber, error) { + trustCenter := compliancepage.CompliancePageFromContext(ctx) + if trustCenter.MailingListID == nil { + return nil, nil + } + + identity := authn.IdentityFromContext(ctx) + if identity == nil { + return nil, nil + } + + subscriber, err := r.mailman.GetSubscriber(ctx, *trustCenter.MailingListID, identity.EmailAddress) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot get mailing list subscription", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + if subscriber == nil { + return nil, nil + } + + return types.NewMailingListSubscriber(subscriber), nil +} + +// Organization is the resolver for the organization field. +func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) { + return obj.Organization, nil +} + +// Documents is the resolver for the documents field. +func (r *trustCenterResolver) Documents(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.DocumentConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{ + Field: coredata.DocumentOrderFieldTitle, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + documentPage, err := trustService.Documents.ListForOrganizationId(ctx, obj.Organization.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list public documents", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewDocumentConnection(documentPage), nil +} + +// Audits is the resolver for the audits field. +func (r *trustCenterResolver) Audits(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.AuditConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.AuditOrderField]{ + Field: coredata.AuditOrderFieldValidFrom, + Direction: page.OrderDirectionDesc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + auditPage, err := trustService.Audits.ListForOrganizationId(ctx, obj.Organization.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list public audits", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewAuditConnection(auditPage), nil +} + +// Subprocessors is the resolver for the subprocessors field. +func (r *trustCenterResolver) Subprocessors(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SubprocessorConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.VendorOrderField]{ + Field: coredata.VendorOrderFieldName, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + vendorPage, err := trustService.Vendors.ListForOrganizationId(ctx, obj.Organization.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list subprocessors", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewSubprocessorConnection(vendorPage, r, obj.ID), 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) (*types.TrustCenterReferenceConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.TrustCenterReferenceOrderField]{ + Field: coredata.TrustCenterReferenceOrderFieldRank, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + referencePage, err := trustService.TrustCenterReferences.ListForTrustCenterID(ctx, obj.ID, cursor) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list public trust center references", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewTrustCenterReferenceConnection(referencePage), nil +} + +// TrustCenterFiles is the resolver for the trustCenterFiles field. +func (r *trustCenterResolver) TrustCenterFiles(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TrustCenterFileConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.TrustCenterFileOrderField]{ + Field: coredata.TrustCenterFileOrderFieldName, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + filter := coredata.NewTrustCenterFileFilter( + coredata.WithTrustCenterFileVisibilities( + coredata.TrustCenterVisibilityPublic, + coredata.TrustCenterVisibilityPrivate, + ), + ) + trustCenterFilePage, err := trustService.TrustCenterFiles.ListForOrganizationId(ctx, obj.Organization.ID, cursor, filter) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot list public trust center files", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return types.NewTrustCenterFileConnection(trustCenterFilePage), 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) (*types.ComplianceFrameworkConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{ + Field: coredata.ComplianceFrameworkOrderFieldRank, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + cfPage, err := trustService.ComplianceFrameworks.ListByTrustCenterID(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(cfPage), 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) (*types.ComplianceExternalURLConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + pageOrderBy := page.OrderBy[coredata.ComplianceExternalURLOrderField]{ + Field: coredata.ComplianceExternalURLOrderFieldRank, + Direction: page.OrderDirectionAsc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + result, err := trustService.ComplianceExternalURLs.ListForTrustCenterID(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 +} + +// Updates is the resolver for the updates field. +func (r *trustCenterResolver) Updates(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) { + trustService := r.TrustService(ctx, obj.ID.TenantID()) + + tc, err := trustService.TrustCenters.Get(ctx, obj.ID) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot load trust center", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + if tc.MailingListID == nil { + return &types.MailingListUpdateConnection{Edges: []*types.MailingListUpdateEdge{}, PageInfo: &types.PageInfo{}}, nil + } + + pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{ + Field: coredata.MailingListUpdateOrderFieldUpdatedAt, + Direction: page.OrderDirectionDesc, + } + cursor := types.NewCursor(first, after, last, before, pageOrderBy) + + result, err := r.mailman.ListSentMailingListUpdates(ctx, *tc.MailingListID, 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), nil +} + // IsUserAuthorized is the resolver for the isUserAuthorized field. func (r *trustCenterFileResolver) IsUserAuthorized(ctx context.Context, obj *types.TrustCenterFile) (bool, error) { trustService := r.TrustService(ctx, obj.ID.TenantID()) @@ -725,6 +959,9 @@ func (r *Resolver) SubprocessorConnection() schema.SubprocessorConnectionResolve return &subprocessorConnectionResolver{r} } +// TrustCenter returns schema.TrustCenterResolver implementation. +func (r *Resolver) TrustCenter() schema.TrustCenterResolver { return &trustCenterResolver{r} } + // TrustCenterFile returns schema.TrustCenterFileResolver implementation. func (r *Resolver) TrustCenterFile() schema.TrustCenterFileResolver { return &trustCenterFileResolver{r} @@ -741,5 +978,6 @@ type documentResolver struct{ *Resolver } type frameworkResolver struct{ *Resolver } type reportResolver struct{ *Resolver } type subprocessorConnectionResolver struct{ *Resolver } +type trustCenterResolver struct{ *Resolver } type trustCenterFileResolver struct{ *Resolver } type trustCenterReferenceResolver struct{ *Resolver }