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 }