1131 lines
38 KiB
Go
1131 lines
38 KiB
Go
package console_v1
|
|
|
|
// This file will be automatically regenerated based on the schema, any resolver
|
|
// implementations
|
|
// will be copied through when generating and any unknown code will be moved to the end.
|
|
// Code generated by github.com/99designs/gqlgen version v0.17.94
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/vikstrous/dataloadgen"
|
|
"go.gearno.de/kit/log"
|
|
"go.probo.inc/probo/pkg/accessreview"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
"go.probo.inc/probo/pkg/errorx"
|
|
"go.probo.inc/probo/pkg/page"
|
|
"go.probo.inc/probo/pkg/probo"
|
|
"go.probo.inc/probo/pkg/server/api/authn"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
|
"go.probo.inc/probo/pkg/server/gqlutils"
|
|
)
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *accessReviewCampaignResolver) Organization(ctx context.Context, obj *types.AccessReviewCampaign) (*types.Organization, error) {
|
|
if _, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Sources is the resolver for the sources field.
|
|
func (r *accessReviewCampaignResolver) Sources(ctx context.Context, obj *types.AccessReviewCampaign) ([]*types.AccessReviewCampaignSource, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaignSources, err := r.accessReview.ListCampaignSources(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list campaign sources", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
result := make([]*types.AccessReviewCampaignSource, len(campaignSources))
|
|
for i, campaignSource := range campaignSources {
|
|
result[i] = types.NewAccessReviewCampaignSource(campaignSource)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Entries is the resolver for the entries field.
|
|
func (r *accessReviewCampaignResolver) Entries(ctx context.Context, obj *types.AccessReviewCampaign, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessReviewEntryOrder, filter *coredata.AccessReviewEntryFilter) (*types.AccessReviewEntryConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionEntryList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessReviewEntryOrderField]{
|
|
Field: coredata.AccessReviewEntryOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessReviewEntryOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.ListEntriesForCampaignID(ctx, scope, obj.ID, cursor, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list access entries", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewEntryConnection(p, r, obj.ID, nil, filter), nil
|
|
}
|
|
|
|
// Statistics is the resolver for the statistics field.
|
|
func (r *accessReviewCampaignResolver) Statistics(ctx context.Context, obj *types.AccessReviewCampaign) (*types.AccessReviewStatistics, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionEntryList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stats, err := r.accessReview.CampaignStatistics(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get campaign statistics", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewStatistics(stats), nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessReviewCampaignResolver) Permission(ctx context.Context, obj *types.AccessReviewCampaign, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessReviewCampaignConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessReviewCampaignConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, accessreview.ActionCampaignList)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.accessReview.CountCampaignsForOrganizationID(ctx, scope, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count access review campaigns", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Campaign is the resolver for the campaign field.
|
|
func (r *accessReviewCampaignSourceResolver) Campaign(ctx context.Context, obj *types.AccessReviewCampaignSource) (*types.AccessReviewCampaign, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.GetCampaign(ctx, scope, obj.Campaign.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewCampaign(campaign), nil
|
|
}
|
|
|
|
// Source is the resolver for the source field.
|
|
func (r *accessReviewCampaignSourceResolver) Source(ctx context.Context, obj *types.AccessReviewCampaignSource) (*types.AccessReviewSource, error) {
|
|
if obj.SourceID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
source, err := r.accessReview.GetSource(ctx, scope, *obj.SourceID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get access review source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewSource(source), nil
|
|
}
|
|
|
|
// FetchAttempts is the resolver for the fetchAttempts field.
|
|
func (r *accessReviewCampaignSourceResolver) FetchAttempts(ctx context.Context, obj *types.AccessReviewCampaignSource, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessReviewCampaignSourceFetchAttemptOrder) (*types.AccessReviewCampaignSourceFetchAttemptConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessReviewCampaignSourceFetchAttemptOrderField]{
|
|
Field: coredata.AccessReviewCampaignSourceFetchAttemptOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessReviewCampaignSourceFetchAttemptOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.ListFetchAttemptsForCampaignSourceID(ctx, scope, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list fetch attempts", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignSourceFetchAttemptConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// Entries is the resolver for the entries field.
|
|
func (r *accessReviewCampaignSourceResolver) Entries(ctx context.Context, obj *types.AccessReviewCampaignSource, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AccessReviewEntryOrder, filter *coredata.AccessReviewEntryFilter) (*types.AccessReviewEntryConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionEntryList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.AccessReviewEntryOrderField]{
|
|
Field: coredata.AccessReviewEntryOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.AccessReviewEntryOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.accessReview.ListEntriesForCampaignIDAndSourceID(ctx, scope, obj.Campaign.ID, obj.ID, cursor, filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list access entries", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
sourceID := obj.ID
|
|
|
|
return types.NewAccessReviewEntryConnection(p, r, obj.Campaign.ID, &sourceID, filter), nil
|
|
}
|
|
|
|
// Statistics is the resolver for the statistics field.
|
|
func (r *accessReviewCampaignSourceResolver) Statistics(ctx context.Context, obj *types.AccessReviewCampaignSource) (*types.AccessReviewStatistics, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionEntryList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stats, err := r.accessReview.CampaignSourceStatistics(ctx, scope, obj.Campaign.ID, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get source statistics", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewStatistics(stats), nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessReviewCampaignSourceFetchAttemptConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessReviewCampaignSourceFetchAttemptConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
count, err := r.accessReview.CountFetchAttemptsForCampaignSourceID(ctx, scope, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count fetch attempts", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// Campaign is the resolver for the campaign field.
|
|
func (r *accessReviewEntryResolver) Campaign(ctx context.Context, obj *types.AccessReviewEntry) (*types.AccessReviewCampaign, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.GetCampaign(ctx, scope, obj.Campaign.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewCampaign(campaign), nil
|
|
}
|
|
|
|
// CampaignSource is the resolver for the campaignSource field.
|
|
func (r *accessReviewEntryResolver) CampaignSource(ctx context.Context, obj *types.AccessReviewEntry) (*types.AccessReviewCampaignSource, error) {
|
|
scope, err := r.authorize(ctx, obj.Campaign.ID, accessreview.ActionCampaignGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaignSource, err := r.accessReview.GetCampaignSource(ctx, scope, obj.CampaignSource.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get campaign source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewAccessReviewCampaignSource(campaignSource), nil
|
|
}
|
|
|
|
// DecisionHistory is the resolver for the decisionHistory field.
|
|
func (r *accessReviewEntryResolver) DecisionHistory(ctx context.Context, obj *types.AccessReviewEntry) ([]*types.AccessReviewEntryDecisionHistoryEntry, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionEntryGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
histories, err := r.accessReview.EntryDecisionHistory(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot get decision history", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
result := make([]*types.AccessReviewEntryDecisionHistoryEntry, len(histories))
|
|
for i, h := range histories {
|
|
result[i] = types.NewAccessReviewEntryDecisionHistoryEntry(h)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessReviewEntryResolver) Permission(ctx context.Context, obj *types.AccessReviewEntry, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessReviewEntryConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessReviewEntryConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, accessreview.ActionEntryList)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *accessReviewCampaignResolver:
|
|
count, err := r.accessReview.CountEntriesForCampaignID(ctx, scope, obj.ParentID, obj.Filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count access entries", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
case *accessReviewCampaignSourceResolver:
|
|
count, err := r.accessReview.CountEntriesForCampaignIDAndSourceID(ctx, scope, obj.ParentID, *obj.SourceID, obj.Filter)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count access entries", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// Organization is the resolver for the organization field.
|
|
func (r *accessReviewSourceResolver) Organization(ctx context.Context, obj *types.AccessReviewSource) (*types.Organization, error) {
|
|
if _, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
organization, err := loaders.Organization.Load(ctx, obj.Organization.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load organization", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
|
|
// Connector is the resolver for the connector field.
|
|
func (r *accessReviewSourceResolver) Connector(ctx context.Context, obj *types.AccessReviewSource) (*types.Connector, error) {
|
|
if obj.ConnectorID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionSourceGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
connector, err := r.probo.Connectors.Get(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get connector", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewConnector(connector), nil
|
|
}
|
|
|
|
// ProviderOrganizations is the resolver for the providerOrganizations field.
|
|
func (r *accessReviewSourceResolver) ProviderOrganizations(ctx context.Context, obj *types.AccessReviewSource) ([]*types.ProviderOrganization, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionSourceGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.ConnectorID == nil {
|
|
return []*types.ProviderOrganization{}, nil
|
|
}
|
|
|
|
orgs, err := r.accessReview.ProviderOrganizations(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]*types.ProviderOrganization, len(orgs))
|
|
for i, o := range orgs {
|
|
result[i] = &types.ProviderOrganization{Slug: o.Slug, DisplayName: o.DisplayName}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// NeedsConfiguration is the resolver for the needsConfiguration field.
|
|
//
|
|
// True when the provider has a picker UI (NeedsPicker) AND the user has
|
|
// not yet picked an org. 2-auto providers (PagerDuty, Vercel) always
|
|
// return false: the identifier is captured during the OAuth callback,
|
|
// not via a follow-up configure mutation.
|
|
func (r *accessReviewSourceResolver) NeedsConfiguration(ctx context.Context, obj *types.AccessReviewSource) (bool, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionSourceGet)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if obj.ConnectorID == nil {
|
|
return false, nil
|
|
}
|
|
|
|
needsConfiguration, err := r.accessReview.SourceNeedsConfiguration(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return false, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot determine access source configuration", log.Error(err))
|
|
|
|
return false, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return needsConfiguration, nil
|
|
}
|
|
|
|
// ConnectionStatus is the resolver for the connectionStatus field.
|
|
//
|
|
// Returns RECONNECT_REQUIRED when the connector's stored OAuth grant is
|
|
// missing scopes required by the current provider registration (e.g. a newly
|
|
// added Graph permission), DISCONNECTED when the credential probe fails, and
|
|
// CONNECTED when the grant is usable as-is.
|
|
func (r *accessReviewSourceResolver) ConnectionStatus(ctx context.Context, obj *types.AccessReviewSource) (types.AccessReviewSourceConnectionStatus, error) {
|
|
if obj.ConnectorID == nil {
|
|
return types.AccessReviewSourceConnectionStatusNotApplicable, nil
|
|
}
|
|
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionSourceGet)
|
|
if err != nil {
|
|
return types.AccessReviewSourceConnectionStatusNotApplicable, err
|
|
}
|
|
|
|
httpClient, dbConnector, err := r.accessReview.ConnectorHTTPClient(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return types.AccessReviewSourceConnectionStatusNotApplicable, nil
|
|
}
|
|
|
|
return types.AccessReviewSourceConnectionStatusDisconnected, nil
|
|
}
|
|
|
|
// Creating an HTTP client may succeed even with an expired or invalid
|
|
// credential (e.g. no refresh token available, or a dead API key).
|
|
// When the provider registers a probe, make a lightweight request to
|
|
// verify the credential is actually accepted.
|
|
if err := r.providerRegistry.ProbeConnection(ctx, httpClient, dbConnector); err != nil {
|
|
return types.AccessReviewSourceConnectionStatusDisconnected, nil
|
|
}
|
|
|
|
needsReconnect, err := r.accessReview.SourceNeedsReconnect(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return types.AccessReviewSourceConnectionStatusNotApplicable, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot determine access source reconnect requirement", log.Error(err))
|
|
|
|
return types.AccessReviewSourceConnectionStatusNotApplicable, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if needsReconnect {
|
|
return types.AccessReviewSourceConnectionStatusReconnectRequired, nil
|
|
}
|
|
|
|
return types.AccessReviewSourceConnectionStatusConnected, nil
|
|
}
|
|
|
|
// SelectedOrganization is the resolver for the selectedOrganization field.
|
|
func (r *accessReviewSourceResolver) SelectedOrganization(ctx context.Context, obj *types.AccessReviewSource) (*string, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, accessreview.ActionSourceGet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if obj.ConnectorID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
slug, err := r.accessReview.SelectedOrganizationSlug(ctx, scope, *obj.ConnectorID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get selected organization", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if slug == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
return &slug, nil
|
|
}
|
|
|
|
// Permission is the resolver for the permission field.
|
|
func (r *accessReviewSourceResolver) Permission(ctx context.Context, obj *types.AccessReviewSource, action string) (bool, error) {
|
|
return r.Resolver.Permission(ctx, obj, action)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *accessReviewSourceConnectionResolver) TotalCount(ctx context.Context, obj *types.AccessReviewSourceConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, accessreview.ActionSourceList)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.accessReview.CountSourcesForOrganizationID(ctx, scope, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count access sources", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "unsupported resolver", log.String("resolver", fmt.Sprintf("%T", obj.Resolver)))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// CreateAccessReviewSource is the resolver for the createAccessReviewSource field.
|
|
func (r *mutationResolver) CreateAccessReviewSource(ctx context.Context, input types.CreateAccessReviewSourceInput) (*types.CreateAccessReviewSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.OrganizationID, accessreview.ActionSourceCreate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
source, err := r.accessReview.CreateSource(
|
|
ctx,
|
|
scope,
|
|
accessreview.CreateAccessReviewSourceRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
ConnectorID: input.ConnectorID,
|
|
Name: input.Name,
|
|
CsvData: input.CSVData,
|
|
},
|
|
)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot create access source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
r.accessReview.AutoSelectDefaultOrganization(ctx, scope, source)
|
|
|
|
return &types.CreateAccessReviewSourcePayload{
|
|
AccessReviewSourceEdge: types.NewAccessReviewSourceEdge(source, coredata.AccessReviewSourceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAccessReviewSource is the resolver for the updateAccessReviewSource field.
|
|
func (r *mutationResolver) UpdateAccessReviewSource(ctx context.Context, input types.UpdateAccessReviewSourceInput) (*types.UpdateAccessReviewSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewSourceID, accessreview.ActionSourceUpdate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
source, err := r.accessReview.UpdateSource(
|
|
ctx,
|
|
scope,
|
|
accessreview.UpdateAccessReviewSourceRequest{
|
|
AccessReviewSourceID: input.AccessReviewSourceID,
|
|
Name: gqlutils.UnwrapOmittable(input.Name),
|
|
ConnectorID: gqlutils.UnwrapOmittable(input.ConnectorID),
|
|
CsvData: gqlutils.UnwrapOmittable(input.CSVData),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot update access source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// A connector was just (re)linked: default its org so the source is usable
|
|
// right away. Skipped on name/CSV-only updates to avoid a needless
|
|
// provider round-trip.
|
|
if input.ConnectorID.IsSet() {
|
|
r.accessReview.AutoSelectDefaultOrganization(ctx, scope, source)
|
|
}
|
|
|
|
return &types.UpdateAccessReviewSourcePayload{
|
|
AccessReviewSource: types.NewAccessReviewSource(source),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAccessReviewSource is the resolver for the deleteAccessReviewSource field.
|
|
func (r *mutationResolver) DeleteAccessReviewSource(ctx context.Context, input types.DeleteAccessReviewSourceInput) (*types.DeleteAccessReviewSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewSourceID, accessreview.ActionSourceDelete)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.accessReview.DeleteSource(ctx, scope, input.AccessReviewSourceID); err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot delete access source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteAccessReviewSourcePayload{
|
|
DeletedAccessReviewSourceID: input.AccessReviewSourceID,
|
|
}, nil
|
|
}
|
|
|
|
// ConfigureAccessReviewSource is the resolver for the configureAccessReviewSource field.
|
|
func (r *mutationResolver) ConfigureAccessReviewSource(ctx context.Context, input types.ConfigureAccessReviewSourceInput) (*types.ConfigureAccessReviewSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewSourceID, accessreview.ActionSourceUpdate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
source, err := r.accessReview.ConfigureAccessReviewSource(
|
|
ctx,
|
|
scope,
|
|
accessreview.ConfigureAccessReviewSourceRequest{
|
|
AccessReviewSourceID: input.AccessReviewSourceID,
|
|
OrganizationSlug: input.OrganizationSlug,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot configure access source", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.ConfigureAccessReviewSourcePayload{
|
|
AccessReviewSource: types.NewAccessReviewSource(source),
|
|
}, nil
|
|
}
|
|
|
|
// CreateAccessReviewCampaign is the resolver for the createAccessReviewCampaign field.
|
|
func (r *mutationResolver) CreateAccessReviewCampaign(ctx context.Context, input types.CreateAccessReviewCampaignInput) (*types.CreateAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.OrganizationID, accessreview.ActionCampaignCreate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var description string
|
|
if input.Description != nil {
|
|
description = *input.Description
|
|
}
|
|
|
|
campaign, err := r.accessReview.CreateCampaign(
|
|
ctx,
|
|
scope,
|
|
accessreview.CreateAccessReviewCampaignRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: description,
|
|
AccessReviewSourceIDs: input.AccessReviewSourceIds,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot create access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateAccessReviewCampaignPayload{
|
|
AccessReviewCampaignEdge: types.NewAccessReviewCampaignEdge(campaign, coredata.AccessReviewCampaignOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateAccessReviewCampaign is the resolver for the updateAccessReviewCampaign field.
|
|
func (r *mutationResolver) UpdateAccessReviewCampaign(ctx context.Context, input types.UpdateAccessReviewCampaignInput) (*types.UpdateAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignUpdate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.UpdateCampaign(
|
|
ctx,
|
|
scope,
|
|
accessreview.UpdateAccessReviewCampaignRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
Name: gqlutils.UnwrapOmittable(input.Name),
|
|
Description: gqlutils.UnwrapOmittable(input.Description),
|
|
AccessReviewSourceIDs: gqlutils.UnwrapOmittable(input.AccessReviewSourceIds),
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errorx.AnyOf(err, accessreview.ErrCampaignNotDraft) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot update access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.UpdateAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteAccessReviewCampaign is the resolver for the deleteAccessReviewCampaign field.
|
|
func (r *mutationResolver) DeleteAccessReviewCampaign(ctx context.Context, input types.DeleteAccessReviewCampaignInput) (*types.DeleteAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignDelete)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.accessReview.DeleteCampaign(ctx, scope, input.AccessReviewCampaignID); err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errors.Is(err, accessreview.ErrCampaignNotDeletable) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot delete access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteAccessReviewCampaignPayload{
|
|
DeletedAccessReviewCampaignID: input.AccessReviewCampaignID,
|
|
}, nil
|
|
}
|
|
|
|
// StartAccessReviewCampaign is the resolver for the startAccessReviewCampaign field.
|
|
func (r *mutationResolver) StartAccessReviewCampaign(ctx context.Context, input types.StartAccessReviewCampaignInput) (*types.StartAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignStart)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.StartCampaign(ctx, scope, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
if errorx.AnyOf(
|
|
err,
|
|
accessreview.ErrCampaignMissingSources,
|
|
accessreview.ErrCampaignNotDraft,
|
|
) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot start access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.StartAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// CloseAccessReviewCampaign is the resolver for the closeAccessReviewCampaign field.
|
|
func (r *mutationResolver) CloseAccessReviewCampaign(ctx context.Context, input types.CloseAccessReviewCampaignInput) (*types.CloseAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignClose)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.CloseCampaign(ctx, scope, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
if errors.Is(err, accessreview.ErrCampaignNotPendingActions) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot close access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CloseAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// CancelAccessReviewCampaign is the resolver for the cancelAccessReviewCampaign field.
|
|
func (r *mutationResolver) CancelAccessReviewCampaign(ctx context.Context, input types.CancelAccessReviewCampaignInput) (*types.CancelAccessReviewCampaignPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignCancel)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.CancelCampaign(ctx, scope, input.AccessReviewCampaignID)
|
|
if err != nil {
|
|
if errorx.AnyOf(err, accessreview.ErrCampaignCompleted, accessreview.ErrCampaignCancelled) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot cancel access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CancelAccessReviewCampaignPayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// AddAccessReviewCampaignSource is the resolver for the addAccessReviewCampaignSource field.
|
|
func (r *mutationResolver) AddAccessReviewCampaignSource(ctx context.Context, input types.AddAccessReviewCampaignSourceInput) (*types.AddAccessReviewCampaignSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignAddSource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.AddCampaignSource(
|
|
ctx,
|
|
scope,
|
|
accessreview.AddCampaignSourceRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
AccessReviewSourceID: input.AccessReviewSourceID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errors.Is(err, accessreview.ErrCampaignNotDraft) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot add scope source to access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.AddAccessReviewCampaignSourcePayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// RemoveAccessReviewCampaignSource is the resolver for the removeAccessReviewCampaignSource field.
|
|
func (r *mutationResolver) RemoveAccessReviewCampaignSource(ctx context.Context, input types.RemoveAccessReviewCampaignSourceInput) (*types.RemoveAccessReviewCampaignSourcePayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewCampaignID, accessreview.ActionCampaignRemoveSource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
campaign, err := r.accessReview.RemoveCampaignSource(
|
|
ctx,
|
|
scope,
|
|
accessreview.RemoveCampaignSourceRequest{
|
|
CampaignID: input.AccessReviewCampaignID,
|
|
AccessReviewSourceID: input.AccessReviewSourceID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, accessreview.ErrCampaignNotDraft) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot remove scope source from access review campaign", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RemoveAccessReviewCampaignSourcePayload{
|
|
AccessReviewCampaign: types.NewAccessReviewCampaign(campaign),
|
|
}, nil
|
|
}
|
|
|
|
// RecordAccessReviewEntryDecision is the resolver for the recordAccessReviewEntryDecision field.
|
|
func (r *mutationResolver) RecordAccessReviewEntryDecision(ctx context.Context, input types.RecordAccessReviewEntryDecisionInput) (*types.RecordAccessReviewEntryDecisionPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewEntryID, accessreview.ActionEntryDecide)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
entry, err := r.accessReview.RecordDecision(
|
|
ctx,
|
|
scope,
|
|
accessreview.RecordAccessReviewEntryDecisionRequest{
|
|
EntryID: input.AccessReviewEntryID,
|
|
Decision: input.Decision,
|
|
DecisionNote: input.DecisionNote,
|
|
DecidedByID: &authn.IdentityFromContext(ctx).ID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot record access entry decision", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RecordAccessReviewEntryDecisionPayload{
|
|
AccessReviewEntry: types.NewAccessReviewEntry(entry),
|
|
}, nil
|
|
}
|
|
|
|
// RecordAccessReviewEntryDecisions is the resolver for the recordAccessReviewEntryDecisions field.
|
|
func (r *mutationResolver) RecordAccessReviewEntryDecisions(ctx context.Context, input types.RecordAccessReviewEntryDecisionsInput) (*types.RecordAccessReviewEntryDecisionsPayload, error) {
|
|
if len(input.Decisions) == 0 {
|
|
return &types.RecordAccessReviewEntryDecisionsPayload{
|
|
AccessReviewEntries: []*types.AccessReviewEntry{},
|
|
}, nil
|
|
}
|
|
|
|
const maxBatchSize = 100
|
|
if len(input.Decisions) > maxBatchSize {
|
|
return nil, fmt.Errorf("cannot record decisions: batch size %d exceeds maximum of %d", len(input.Decisions), maxBatchSize)
|
|
}
|
|
|
|
// Authorize each entry individually to prevent cross-org bypass.
|
|
for _, d := range input.Decisions {
|
|
_, err := r.authorize(ctx, d.AccessReviewEntryID, accessreview.ActionEntryDecide)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
identity := authn.IdentityFromContext(ctx)
|
|
if identity == nil {
|
|
return nil, fmt.Errorf("no identity in context")
|
|
}
|
|
|
|
tenantID := input.Decisions[0].AccessReviewEntryID.TenantID()
|
|
scope := coredata.NewScope(tenantID)
|
|
decidedByID := &identity.ID
|
|
|
|
decisions := make([]accessreview.RecordAccessReviewEntryDecisionRequest, len(input.Decisions))
|
|
for i, d := range input.Decisions {
|
|
decisions[i] = accessreview.RecordAccessReviewEntryDecisionRequest{
|
|
EntryID: d.AccessReviewEntryID,
|
|
Decision: d.Decision,
|
|
DecisionNote: d.DecisionNote,
|
|
DecidedByID: decidedByID,
|
|
}
|
|
}
|
|
|
|
entries, err := r.accessReview.RecordDecisions(ctx, scope, decisions)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot record access entry decisions", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
accessEntries := make([]*types.AccessReviewEntry, len(entries))
|
|
for i, e := range entries {
|
|
accessEntries[i] = types.NewAccessReviewEntry(e)
|
|
}
|
|
|
|
return &types.RecordAccessReviewEntryDecisionsPayload{
|
|
AccessReviewEntries: accessEntries,
|
|
}, nil
|
|
}
|
|
|
|
// FlagAccessReviewEntry is the resolver for the flagAccessReviewEntry field.
|
|
func (r *mutationResolver) FlagAccessReviewEntry(ctx context.Context, input types.FlagAccessReviewEntryInput) (*types.FlagAccessReviewEntryPayload, error) {
|
|
scope, err := r.authorize(ctx, input.AccessReviewEntryID, accessreview.ActionEntryFlag)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
entry, err := r.accessReview.FlagEntry(ctx, scope, accessreview.FlagAccessReviewEntryRequest{
|
|
EntryID: input.AccessReviewEntryID,
|
|
Flags: input.Flags,
|
|
FlagReasons: input.FlagReasons,
|
|
})
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot flag access entry", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.FlagAccessReviewEntryPayload{
|
|
AccessReviewEntry: types.NewAccessReviewEntry(entry),
|
|
}, nil
|
|
}
|
|
|
|
// AccessReviewCampaign returns schema.AccessReviewCampaignResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaign() schema.AccessReviewCampaignResolver {
|
|
return &accessReviewCampaignResolver{r}
|
|
}
|
|
|
|
// AccessReviewCampaignConnection returns schema.AccessReviewCampaignConnectionResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaignConnection() schema.AccessReviewCampaignConnectionResolver {
|
|
return &accessReviewCampaignConnectionResolver{r}
|
|
}
|
|
|
|
// AccessReviewCampaignSource returns schema.AccessReviewCampaignSourceResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaignSource() schema.AccessReviewCampaignSourceResolver {
|
|
return &accessReviewCampaignSourceResolver{r}
|
|
}
|
|
|
|
// AccessReviewCampaignSourceFetchAttemptConnection returns schema.AccessReviewCampaignSourceFetchAttemptConnectionResolver implementation.
|
|
func (r *Resolver) AccessReviewCampaignSourceFetchAttemptConnection() schema.AccessReviewCampaignSourceFetchAttemptConnectionResolver {
|
|
return &accessReviewCampaignSourceFetchAttemptConnectionResolver{r}
|
|
}
|
|
|
|
// AccessReviewEntry returns schema.AccessReviewEntryResolver implementation.
|
|
func (r *Resolver) AccessReviewEntry() schema.AccessReviewEntryResolver {
|
|
return &accessReviewEntryResolver{r}
|
|
}
|
|
|
|
// AccessReviewEntryConnection returns schema.AccessReviewEntryConnectionResolver implementation.
|
|
func (r *Resolver) AccessReviewEntryConnection() schema.AccessReviewEntryConnectionResolver {
|
|
return &accessReviewEntryConnectionResolver{r}
|
|
}
|
|
|
|
// AccessReviewSource returns schema.AccessReviewSourceResolver implementation.
|
|
func (r *Resolver) AccessReviewSource() schema.AccessReviewSourceResolver {
|
|
return &accessReviewSourceResolver{r}
|
|
}
|
|
|
|
// AccessReviewSourceConnection returns schema.AccessReviewSourceConnectionResolver implementation.
|
|
func (r *Resolver) AccessReviewSourceConnection() schema.AccessReviewSourceConnectionResolver {
|
|
return &accessReviewSourceConnectionResolver{r}
|
|
}
|
|
|
|
type (
|
|
accessReviewCampaignResolver struct{ *Resolver }
|
|
accessReviewCampaignConnectionResolver struct{ *Resolver }
|
|
accessReviewCampaignSourceResolver struct{ *Resolver }
|
|
accessReviewCampaignSourceFetchAttemptConnectionResolver struct{ *Resolver }
|
|
accessReviewEntryResolver struct{ *Resolver }
|
|
accessReviewEntryConnectionResolver struct{ *Resolver }
|
|
accessReviewSourceResolver struct{ *Resolver }
|
|
accessReviewSourceConnectionResolver struct{ *Resolver }
|
|
)
|