package connect_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" "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/iam/scim/bridge/provider/microsoft365" "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" ) // CreateOrganization is the resolver for the createOrganization field. func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) { identity := authn.IdentityFromContext(ctx) // FIXME check email domain and related IDP config // if ok := r.authorize(ctx, identity.ID, iam.ActionOrganizationCreate); !ok { // return nil, nil // } var ( logoFile *iam.UploadedFile horizontalLogoFile *iam.UploadedFile ) if input.LogoFile != nil { logoFile = &iam.UploadedFile{ Content: input.LogoFile.File, Filename: input.LogoFile.Filename, ContentType: input.LogoFile.ContentType, Size: input.LogoFile.Size, } } if input.HorizontalLogoFile != nil { horizontalLogoFile = &iam.UploadedFile{ Content: input.HorizontalLogoFile.File, Filename: input.HorizontalLogoFile.Filename, ContentType: input.HorizontalLogoFile.ContentType, Size: input.HorizontalLogoFile.Size, } } organization, profile, err := r.iam.OrganizationService.CreateOrganization( ctx, identity.ID, &iam.CreateOrganizationRequest{ Name: input.Name, LogoFile: logoFile, HorizontalLogoFile: horizontalLogoFile, }, ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(ctx, err) } r.logger.ErrorCtx(ctx, "cannot create organization", log.Error(err)) return nil, gqlutils.Internal(ctx) } return &types.CreateOrganizationPayload{ Organization: types.NewOrganization(organization), Profile: types.NewProfile(profile), }, nil } // UpdateOrganization is the resolver for the updateOrganization field. func (r *mutationResolver) UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error) { if _, err := r.authorize(ctx, input.OrganizationID, iam.ActionOrganizationUpdate); err != nil { return nil, err } req := &iam.UpdateOrganizationRequest{ Name: input.Name, } if input.LogoFile != nil { req.LogoFile = &iam.UploadedFile{ Filename: input.LogoFile.Filename, ContentType: input.LogoFile.ContentType, Size: input.LogoFile.Size, Content: input.LogoFile.File, } } if input.HorizontalLogoFile != nil { req.HorizontalLogoFile = &iam.UploadedFile{ Filename: input.HorizontalLogoFile.Filename, ContentType: input.HorizontalLogoFile.ContentType, Size: input.HorizontalLogoFile.Size, Content: input.HorizontalLogoFile.File, } } organization, err := r.iam.OrganizationService.UpdateOrganization( ctx, input.OrganizationID, req, ) if err != nil { r.logger.ErrorCtx(ctx, "cannot update organization", log.Error(err)) return nil, gqlutils.Internal(ctx) } return &types.UpdateOrganizationPayload{ Organization: &types.Organization{ ID: organization.ID, Name: organization.Name, CreatedAt: organization.CreatedAt, UpdatedAt: organization.UpdatedAt, }, }, nil } // DeleteOrganization is the resolver for the deleteOrganization field. func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) { if _, err := r.authorize(ctx, input.OrganizationID, iam.ActionOrganizationDelete); err != nil { return nil, err } err := r.iam.OrganizationService.DeleteOrganization(ctx, input.OrganizationID) if err != nil { r.logger.ErrorCtx(ctx, "cannot delete organization", log.Error(err)) return nil, gqlutils.Internal(ctx) } return &types.DeleteOrganizationPayload{DeletedOrganizationID: input.OrganizationID}, nil } // DeleteOrganizationHorizontalLogo is the resolver for the deleteOrganizationHorizontalLogo field. func (r *mutationResolver) DeleteOrganizationHorizontalLogo(ctx context.Context, input types.DeleteOrganizationHorizontalLogoInput) (*types.DeleteOrganizationHorizontalLogoPayload, error) { panic(fmt.Errorf("not implemented: DeleteOrganizationHorizontalLogo - deleteOrganizationHorizontalLogo")) } // Logo is the resolver for the logo field. func (r *organizationResolver) Logo(ctx context.Context, obj *types.Organization) (*types.File, error) { file, err := r.iam.OrganizationService.LogoFile(ctx, obj.ID) if err != nil { r.logger.ErrorCtx(ctx, "cannot load logo file", log.Error(err)) return nil, gqlutils.Internal(ctx) } if file == nil { return nil, nil } return types.NewFile(file, r.fileManager), nil } // HorizontalLogo is the resolver for the horizontalLogo field. func (r *organizationResolver) HorizontalLogo(ctx context.Context, obj *types.Organization) (*types.File, error) { file, err := r.iam.OrganizationService.HorizontalLogoFile(ctx, obj.ID) if err != nil { r.logger.ErrorCtx(ctx, "cannot load horizontal logo file", log.Error(err)) return nil, gqlutils.Internal(ctx) } if file == nil { return nil, nil } return types.NewFile(file, r.fileManager), 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 } filters := coredata.NewMembershipProfileFilter(nil).WithMembership() if filter != nil { filters = coredata.NewMembershipProfileFilter(filter.ContractEnded).WithMembership() if len(filter.States) > 0 { filters.WithStates(filter.States...) } if filter.Query != nil { filters.WithQuery(filter.Query) } if filter.Role != nil { filters.WithRole(*filter.Role) } if filter.Kind != nil { filters.WithKind(filter.Kind) } } 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.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 } // 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 { if _, ok := errors.AsType[*iam.ErrNoSCIMConfigurationFound](err); ok { 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, }, { Type: coredata.SCIMBridgeTypeMicrosoft365, Oauth2Scopes: microsoft365.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 { if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); ok { return nil, gqlutils.NotFound(ctx, err) } r.logger.ErrorCtx(ctx, "cannot get profile", log.Error(err)) return nil, gqlutils.Internal(ctx) } return types.NewProfile(profile), nil } // Permission is the resolver for the permission field. func (r *organizationResolver) Permission(ctx context.Context, obj *types.Organization, action string, attributes map[string]any) (bool, error) { return r.permission(ctx, obj, action, attributes) } // Organization returns schema.OrganizationResolver implementation. func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} } type organizationResolver struct{ *Resolver }