2053 lines
71 KiB
Go
2053 lines
71 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.70
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/getprobo/probo/pkg/coredata"
|
|
"github.com/getprobo/probo/pkg/gid"
|
|
"github.com/getprobo/probo/pkg/page"
|
|
"github.com/getprobo/probo/pkg/probo"
|
|
"github.com/getprobo/probo/pkg/server/api/console/v1/schema"
|
|
"github.com/getprobo/probo/pkg/server/api/console/v1/types"
|
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
)
|
|
|
|
// Mesures is the resolver for the mesures field.
|
|
func (r *controlResolver) Mesures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MesureOrderBy) (*types.MesureConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MesureOrderField]{
|
|
Field: coredata.MesureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MesureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Mesures.ListForControlID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list mesures: %w", err)
|
|
}
|
|
|
|
return types.NewMesureConnection(page), nil
|
|
}
|
|
|
|
// Policies is the resolver for the policies field.
|
|
func (r *controlResolver) Policies(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyOrderBy) (*types.PolicyConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: coredata.PolicyOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Policies.ListForControlID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list policies: %w", err)
|
|
}
|
|
|
|
return types.NewPolicyConnection(page), nil
|
|
}
|
|
|
|
// FileURL is the resolver for the fileUrl field.
|
|
func (r *evidenceResolver) FileURL(ctx context.Context, obj *types.Evidence) (*string, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
if obj.Type == coredata.EvidenceTypeLink {
|
|
return obj.URL, nil
|
|
}
|
|
|
|
fileURL, err := svc.Evidences.GenerateFileURL(ctx, obj.ID, 15*time.Minute)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot generate file URL: %w", err)
|
|
}
|
|
|
|
result := *fileURL
|
|
return &result, nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Controls.ListForFrameworkID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list controls: %w", err)
|
|
}
|
|
|
|
return types.NewControlConnection(page), nil
|
|
}
|
|
|
|
// Tasks is the resolver for the tasks field.
|
|
func (r *mesureResolver) Tasks(ctx context.Context, obj *types.Mesure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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 := svc.Tasks.ListForMesureID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list mesure tasks: %w", err)
|
|
}
|
|
|
|
return types.NewTaskConnection(page), nil
|
|
}
|
|
|
|
// Risks is the resolver for the risks field.
|
|
func (r *mesureResolver) Risks(ctx context.Context, obj *types.Mesure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy) (*types.RiskConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Risks.ListForMesureID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list mesure risks: %w", err)
|
|
}
|
|
|
|
return types.NewRiskConnection(page), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *mesureResolver) Controls(ctx context.Context, obj *types.Mesure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Controls.ListForMesureID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot list mesure controls: %w", err)
|
|
}
|
|
|
|
return types.NewControlConnection(page), nil
|
|
}
|
|
|
|
// CreateOrganization is the resolver for the createOrganization field.
|
|
func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) {
|
|
svc := r.proboSvc.WithTenant(gid.NewTenantID())
|
|
|
|
organization, err := svc.Organizations.Create(ctx, probo.CreateOrganizationRequest{
|
|
Name: input.Name,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create organization: %w", err)
|
|
}
|
|
|
|
err = r.usrmgrSvc.EnrollUserInOrganization(ctx, UserFromContext(ctx).ID, organization.ID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot add user to organization: %w", err)
|
|
}
|
|
|
|
tenantIDs, _ := ctx.Value(userTenantContextKey).(*[]gid.TenantID)
|
|
*tenantIDs = append(*tenantIDs, organization.ID.TenantID())
|
|
|
|
_, err = svc.Peoples.Create(
|
|
ctx,
|
|
probo.CreatePeopleRequest{
|
|
OrganizationID: organization.ID,
|
|
UserID: &UserFromContext(ctx).ID,
|
|
FullName: UserFromContext(ctx).FullName,
|
|
PrimaryEmailAddress: UserFromContext(ctx).EmailAddress,
|
|
AdditionalEmailAddresses: []string{},
|
|
Kind: coredata.PeopleKindEmployee,
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create people: %w", err)
|
|
}
|
|
|
|
return &types.CreateOrganizationPayload{
|
|
OrganizationEdge: types.NewOrganizationEdge(organization, coredata.OrganizationOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateOrganization is the resolver for the updateOrganization field.
|
|
func (r *mutationResolver) UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
req := probo.UpdateOrganizationRequest{
|
|
ID: input.OrganizationID,
|
|
Name: input.Name,
|
|
}
|
|
|
|
if input.Logo != nil {
|
|
req.File = input.Logo.File
|
|
}
|
|
|
|
organization, err := svc.Organizations.Update(ctx, req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot update organization: %w", err)
|
|
}
|
|
|
|
return &types.UpdateOrganizationPayload{
|
|
Organization: types.NewOrganization(organization),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteOrganization is the resolver for the deleteOrganization field.
|
|
func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) {
|
|
panic(fmt.Errorf("not implemented: DeleteOrganization - deleteOrganization"))
|
|
}
|
|
|
|
// ConfirmEmail is the resolver for the confirmEmail field.
|
|
func (r *mutationResolver) ConfirmEmail(ctx context.Context, input types.ConfirmEmailInput) (*types.ConfirmEmailPayload, error) {
|
|
err := r.usrmgrSvc.ConfirmEmail(ctx, input.Token)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.ConfirmEmailPayload{Success: true}, nil
|
|
}
|
|
|
|
// InviteUser is the resolver for the inviteUser field.
|
|
func (r *mutationResolver) InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error) {
|
|
user := UserFromContext(ctx)
|
|
|
|
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list organizations for user: %w", err))
|
|
}
|
|
|
|
for _, organization := range organizations {
|
|
if organization.ID == input.OrganizationID {
|
|
err := r.usrmgrSvc.InviteUser(ctx, input.OrganizationID, input.FullName, input.Email)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.InviteUserPayload{Success: true}, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("organization not found")
|
|
}
|
|
|
|
// RemoveUser is the resolver for the removeUser field.
|
|
func (r *mutationResolver) RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error) {
|
|
user := UserFromContext(ctx)
|
|
|
|
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list organizations for user: %w", err))
|
|
}
|
|
|
|
for _, organization := range organizations {
|
|
if organization.ID == input.OrganizationID {
|
|
err := r.usrmgrSvc.RemoveUser(ctx, input.OrganizationID, input.UserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.RemoveUserPayload{Success: true}, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("organization not found")
|
|
}
|
|
|
|
// CreatePeople is the resolver for the createPeople field.
|
|
func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
people, err := svc.Peoples.Create(ctx, probo.CreatePeopleRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
FullName: input.FullName,
|
|
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
|
AdditionalEmailAddresses: []string{},
|
|
Kind: input.Kind,
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create people: %w", err)
|
|
}
|
|
|
|
return &types.CreatePeoplePayload{
|
|
PeopleEdge: types.NewPeopleEdge(people, coredata.PeopleOrderFieldFullName),
|
|
}, nil
|
|
}
|
|
|
|
// UpdatePeople is the resolver for the updatePeople field.
|
|
func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdatePeopleInput) (*types.UpdatePeoplePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
|
|
|
people, err := svc.Peoples.Update(ctx, probo.UpdatePeopleRequest{
|
|
ID: input.ID,
|
|
FullName: input.FullName,
|
|
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
|
AdditionalEmailAddresses: &input.AdditionalEmailAddresses,
|
|
Kind: input.Kind,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot update people: %w", err)
|
|
}
|
|
|
|
return &types.UpdatePeoplePayload{
|
|
People: types.NewPeople(people),
|
|
}, nil
|
|
}
|
|
|
|
// DeletePeople is the resolver for the deletePeople field.
|
|
func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeletePeopleInput) (*types.DeletePeoplePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PeopleID.TenantID())
|
|
|
|
err := svc.Peoples.Delete(ctx, input.PeopleID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot delete people: %w", err)
|
|
}
|
|
|
|
return &types.DeletePeoplePayload{
|
|
DeletedPeopleID: input.PeopleID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendor is the resolver for the createVendor field.
|
|
func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Create(
|
|
ctx,
|
|
probo.CreateVendorRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
ServiceStartAt: input.ServiceStartAt,
|
|
ServiceTerminationAt: input.ServiceTerminationAt,
|
|
StatusPageURL: input.StatusPageURL,
|
|
TermsOfServiceURL: input.TermsOfServiceURL,
|
|
PrivacyPolicyURL: input.PrivacyPolicyURL,
|
|
ServiceLevelAgreementURL: input.ServiceLevelAgreementURL,
|
|
LegalName: input.LegalName,
|
|
HeadquarterAddress: input.HeadquarterAddress,
|
|
WebsiteURL: input.WebsiteURL,
|
|
Category: input.Category,
|
|
DataProcessingAgreementURL: input.DataProcessingAgreementURL,
|
|
Certifications: input.Certifications,
|
|
SecurityPageURL: input.SecurityPageURL,
|
|
TrustPageURL: input.TrustPageURL,
|
|
BusinessOwnerID: input.BusinessOwnerID,
|
|
SecurityOwnerID: input.SecurityOwnerID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create vendor: %w", err)
|
|
}
|
|
return &types.CreateVendorPayload{
|
|
VendorEdge: types.NewVendorEdge(vendor, coredata.VendorOrderFieldName),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateVendor is the resolver for the updateVendor field.
|
|
func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Update(ctx, probo.UpdateVendorRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
ServiceStartAt: input.ServiceStartAt,
|
|
ServiceTerminationAt: input.ServiceTerminationAt,
|
|
StatusPageURL: input.StatusPageURL,
|
|
TermsOfServiceURL: input.TermsOfServiceURL,
|
|
PrivacyPolicyURL: input.PrivacyPolicyURL,
|
|
ServiceLevelAgreementURL: input.ServiceLevelAgreementURL,
|
|
DataProcessingAgreementURL: input.DataProcessingAgreementURL,
|
|
SecurityPageURL: input.SecurityPageURL,
|
|
TrustPageURL: input.TrustPageURL,
|
|
HeadquarterAddress: input.HeadquarterAddress,
|
|
LegalName: input.LegalName,
|
|
WebsiteURL: input.WebsiteURL,
|
|
Category: input.Category,
|
|
Certifications: input.Certifications,
|
|
BusinessOwnerID: input.BusinessOwnerID,
|
|
SecurityOwnerID: input.SecurityOwnerID,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot update vendor: %w", err)
|
|
}
|
|
|
|
return &types.UpdateVendorPayload{
|
|
Vendor: types.NewVendor(vendor),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendor is the resolver for the deleteVendor field.
|
|
func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID())
|
|
|
|
err := svc.Vendors.Delete(ctx, input.VendorID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot delete vendor: %w", err)
|
|
}
|
|
|
|
return &types.DeleteVendorPayload{
|
|
DeletedVendorID: input.VendorID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateFramework is the resolver for the createFramework field.
|
|
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
framework, err := svc.Frameworks.Create(ctx, probo.CreateFrameworkRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot create framework: %w", err)
|
|
}
|
|
|
|
return &types.CreateFrameworkPayload{
|
|
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateFramework is the resolver for the updateFramework field.
|
|
func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
|
|
|
framework, err := svc.Frameworks.Update(ctx, probo.UpdateFrameworkRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot update framework: %w", err)
|
|
}
|
|
|
|
return &types.UpdateFrameworkPayload{
|
|
Framework: types.NewFramework(framework),
|
|
}, nil
|
|
}
|
|
|
|
// ImportFramework is the resolver for the importFramework field.
|
|
func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
req := probo.ImportFrameworkRequest{}
|
|
if err := json.NewDecoder(input.File.File).Decode(&req.Framework); err != nil {
|
|
return nil, fmt.Errorf("cannot decode framework: %w", err)
|
|
}
|
|
|
|
framework, err := svc.Frameworks.Import(ctx, input.OrganizationID, req)
|
|
if err != nil {
|
|
var errFrameworkReferenceIDAlreadyExists *coredata.ErrFrameworkReferenceIDAlreadyExists
|
|
if errors.As(err, &errFrameworkReferenceIDAlreadyExists) {
|
|
return nil, &gqlerror.Error{
|
|
Err: err,
|
|
Message: fmt.Sprintf("framework %q already exists", req.Framework.Name),
|
|
Extensions: map[string]any{
|
|
"frameworkReferenceId": errFrameworkReferenceIDAlreadyExists.ReferenceID,
|
|
},
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("cannot import framework: %w", err)
|
|
}
|
|
|
|
return &types.ImportFrameworkPayload{
|
|
FrameworkEdge: types.NewFrameworkEdge(framework, coredata.FrameworkOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteFramework is the resolver for the deleteFramework field.
|
|
func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.FrameworkID.TenantID())
|
|
|
|
err := svc.Frameworks.Delete(ctx, input.FrameworkID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot delete framework: %w", err)
|
|
}
|
|
|
|
return &types.DeleteFrameworkPayload{
|
|
DeletedFrameworkID: input.FrameworkID,
|
|
}, nil
|
|
}
|
|
|
|
// // CreateMesure is the resolver for the createMesure field.
|
|
func (r *mutationResolver) CreateMesure(ctx context.Context, input types.CreateMesureInput) (*types.CreateMesurePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
mesure, err := svc.Mesures.Create(ctx, probo.CreateMesureRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create mesure: %w", err))
|
|
}
|
|
|
|
return &types.CreateMesurePayload{
|
|
MesureEdge: types.NewMesureEdge(mesure, coredata.MesureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateMesure is the resolver for the updateMesure field.
|
|
func (r *mutationResolver) UpdateMesure(ctx context.Context, input types.UpdateMesureInput) (*types.UpdateMesurePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
|
|
|
mesure, err := svc.Mesures.Update(ctx, probo.UpdateMesureRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
State: input.State,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot update mesure: %w", err))
|
|
}
|
|
|
|
return &types.UpdateMesurePayload{
|
|
Mesure: types.NewMesure(mesure),
|
|
}, nil
|
|
}
|
|
|
|
// ImportMesure is the resolver for the importMesure field.
|
|
func (r *mutationResolver) ImportMesure(ctx context.Context, input types.ImportMesureInput) (*types.ImportMesurePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
var req probo.ImportMesureRequest
|
|
if err := json.NewDecoder(input.File.File).Decode(&req.Mesures); err != nil {
|
|
return nil, fmt.Errorf("cannot unmarshal mesure: %w", err)
|
|
}
|
|
|
|
mesures, err := svc.Mesures.Import(ctx, input.OrganizationID, req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot import mesure: %w", err)
|
|
}
|
|
|
|
mesureEdges := make([]*types.MesureEdge, len(mesures.Data))
|
|
for i, mesure := range mesures.Data {
|
|
mesureEdges[i] = types.NewMesureEdge(mesure, coredata.MesureOrderFieldCreatedAt)
|
|
}
|
|
|
|
return &types.ImportMesurePayload{
|
|
MesureEdges: mesureEdges,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteMesure is the resolver for the deleteMesure field.
|
|
func (r *mutationResolver) DeleteMesure(ctx context.Context, input types.DeleteMesureInput) (*types.DeleteMesurePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.MesureID.TenantID())
|
|
|
|
err := svc.Mesures.Delete(ctx, input.MesureID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete mesure: %w", err))
|
|
}
|
|
|
|
return &types.DeleteMesurePayload{
|
|
DeletedMesureID: input.MesureID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlMesureMapping is the resolver for the createControlMesureMapping field.
|
|
func (r *mutationResolver) CreateControlMesureMapping(ctx context.Context, input types.CreateControlMesureMappingInput) (*types.CreateControlMesureMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.MesureID.TenantID())
|
|
|
|
err := svc.Controls.CreateMesureMapping(ctx, input.ControlID, input.MesureID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create control mesure mapping: %w", err))
|
|
}
|
|
|
|
return &types.CreateControlMesureMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// CreateControlPolicyMapping is the resolver for the createControlPolicyMapping field.
|
|
func (r *mutationResolver) CreateControlPolicyMapping(ctx context.Context, input types.CreateControlPolicyMappingInput) (*types.CreateControlPolicyMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyID.TenantID())
|
|
|
|
err := svc.Controls.CreatePolicyMapping(ctx, input.ControlID, input.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create control policy mapping: %w", err))
|
|
}
|
|
|
|
return &types.CreateControlPolicyMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlMesureMapping is the resolver for the deleteControlMesureMapping field.
|
|
func (r *mutationResolver) DeleteControlMesureMapping(ctx context.Context, input types.DeleteControlMesureMappingInput) (*types.DeleteControlMesureMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.MesureID.TenantID())
|
|
|
|
err := svc.Controls.DeleteMesureMapping(ctx, input.ControlID, input.MesureID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete control mesure mapping: %w", err))
|
|
}
|
|
|
|
return &types.DeleteControlMesureMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteControlPolicyMapping is the resolver for the deleteControlPolicyMapping field.
|
|
func (r *mutationResolver) DeleteControlPolicyMapping(ctx context.Context, input types.DeleteControlPolicyMappingInput) (*types.DeleteControlPolicyMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyID.TenantID())
|
|
|
|
err := svc.Controls.DeletePolicyMapping(ctx, input.ControlID, input.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete control policy mapping: %w", err))
|
|
}
|
|
|
|
return &types.DeleteControlPolicyMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// CreateTask is the resolver for the createTask field.
|
|
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.MesureID.TenantID())
|
|
|
|
task, err := svc.Tasks.Create(ctx, probo.CreateTaskRequest{
|
|
MesureID: input.MesureID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
TimeEstimate: input.TimeEstimate,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create task: %w", err))
|
|
}
|
|
|
|
return &types.CreateTaskPayload{
|
|
TaskEdge: types.NewTaskEdge(task, coredata.TaskOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateTask is the resolver for the updateTask field.
|
|
func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
task, err := svc.Tasks.Update(ctx, probo.UpdateTaskRequest{
|
|
TaskID: input.TaskID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
State: input.State,
|
|
TimeEstimate: input.TimeEstimate,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot update task: %w", err))
|
|
}
|
|
|
|
return &types.UpdateTaskPayload{
|
|
Task: types.NewTask(task),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteTask is the resolver for the deleteTask field.
|
|
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
err := svc.Tasks.Delete(ctx, input.TaskID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete task: %w", err))
|
|
}
|
|
|
|
return &types.DeleteTaskPayload{
|
|
DeletedTaskID: input.TaskID,
|
|
}, nil
|
|
}
|
|
|
|
// AssignTask is the resolver for the assignTask field.
|
|
func (r *mutationResolver) AssignTask(ctx context.Context, input types.AssignTaskInput) (*types.AssignTaskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
task, err := svc.Tasks.Assign(ctx, input.TaskID, input.AssignedToID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot assign task: %w", err))
|
|
}
|
|
|
|
return &types.AssignTaskPayload{
|
|
Task: types.NewTask(task),
|
|
}, nil
|
|
}
|
|
|
|
// UnassignTask is the resolver for the unassignTask field.
|
|
func (r *mutationResolver) UnassignTask(ctx context.Context, input types.UnassignTaskInput) (*types.UnassignTaskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
task, err := svc.Tasks.Unassign(ctx, input.TaskID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot unassign task: %w", err))
|
|
}
|
|
|
|
return &types.UnassignTaskPayload{
|
|
Task: types.NewTask(task),
|
|
}, nil
|
|
}
|
|
|
|
// CreateRisk is the resolver for the createRisk field.
|
|
func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
risk, err := svc.Risks.Create(
|
|
ctx,
|
|
probo.CreateRiskRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
Treatment: input.Treatment,
|
|
OwnerID: input.OwnerID,
|
|
InherentLikelihood: input.InherentLikelihood,
|
|
InherentImpact: input.InherentImpact,
|
|
ResidualLikelihood: input.ResidualLikelihood,
|
|
ResidualImpact: input.ResidualImpact,
|
|
Note: input.Note,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create risk: %w", err))
|
|
}
|
|
|
|
return &types.CreateRiskPayload{
|
|
RiskEdge: types.NewRiskEdge(risk, coredata.RiskOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateRisk is the resolver for the updateRisk field.
|
|
func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRiskInput) (*types.UpdateRiskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
|
|
|
risk, err := svc.Risks.Update(
|
|
ctx,
|
|
probo.UpdateRiskRequest{
|
|
ID: input.ID,
|
|
Name: input.Name,
|
|
Description: input.Description,
|
|
Category: input.Category,
|
|
Treatment: input.Treatment,
|
|
OwnerID: input.OwnerID,
|
|
InherentLikelihood: input.InherentLikelihood,
|
|
InherentImpact: input.InherentImpact,
|
|
ResidualLikelihood: input.ResidualLikelihood,
|
|
ResidualImpact: input.ResidualImpact,
|
|
Note: input.Note,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot update risk: %w", err))
|
|
}
|
|
|
|
return &types.UpdateRiskPayload{
|
|
Risk: types.NewRisk(risk),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRisk is the resolver for the deleteRisk field.
|
|
func (r *mutationResolver) DeleteRisk(ctx context.Context, input types.DeleteRiskInput) (*types.DeleteRiskPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.RiskID.TenantID())
|
|
|
|
err := svc.Risks.Delete(ctx, input.RiskID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete risk: %w", err))
|
|
}
|
|
|
|
return &types.DeleteRiskPayload{
|
|
DeletedRiskID: input.RiskID,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRiskMesureMapping is the resolver for the createRiskMesureMapping field.
|
|
func (r *mutationResolver) CreateRiskMesureMapping(ctx context.Context, input types.CreateRiskMesureMappingInput) (*types.CreateRiskMesureMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.RiskID.TenantID())
|
|
|
|
err := svc.Risks.CreateMesureMapping(ctx, input.RiskID, input.MesureID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create risk mesure mapping: %w", err))
|
|
}
|
|
|
|
return &types.CreateRiskMesureMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRiskMesureMapping is the resolver for the deleteRiskMesureMapping field.
|
|
func (r *mutationResolver) DeleteRiskMesureMapping(ctx context.Context, input types.DeleteRiskMesureMappingInput) (*types.DeleteRiskMesureMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.RiskID.TenantID())
|
|
|
|
err := svc.Risks.DeleteMesureMapping(ctx, input.RiskID, input.MesureID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete risk mesure mapping: %w", err))
|
|
}
|
|
|
|
return &types.DeleteRiskMesureMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// CreateRiskPolicyMapping is the resolver for the createRiskPolicyMapping field.
|
|
func (r *mutationResolver) CreateRiskPolicyMapping(ctx context.Context, input types.CreateRiskPolicyMappingInput) (*types.CreateRiskPolicyMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.RiskID.TenantID())
|
|
|
|
err := svc.Risks.CreatePolicyMapping(ctx, input.RiskID, input.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create risk policy mapping: %w", err))
|
|
}
|
|
|
|
return &types.CreateRiskPolicyMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteRiskPolicyMapping is the resolver for the deleteRiskPolicyMapping field.
|
|
func (r *mutationResolver) DeleteRiskPolicyMapping(ctx context.Context, input types.DeleteRiskPolicyMappingInput) (*types.DeleteRiskPolicyMappingPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.RiskID.TenantID())
|
|
|
|
err := svc.Risks.DeletePolicyMapping(ctx, input.RiskID, input.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete risk policy mapping: %w", err))
|
|
}
|
|
|
|
return &types.DeleteRiskPolicyMappingPayload{
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// RequestEvidence is the resolver for the requestEvidence field.
|
|
func (r *mutationResolver) RequestEvidence(ctx context.Context, input types.RequestEvidenceInput) (*types.RequestEvidencePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
evidence, err := svc.Evidences.Request(
|
|
ctx,
|
|
probo.RequestEvidenceRequest{
|
|
TaskID: input.TaskID,
|
|
Name: input.Name,
|
|
Type: input.Type,
|
|
Description: input.Description,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot request evidence: %w", err))
|
|
}
|
|
|
|
return &types.RequestEvidencePayload{
|
|
EvidenceEdge: types.NewEvidenceEdge(evidence, coredata.EvidenceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// FulfillEvidence is the resolver for the fulfillEvidence field.
|
|
func (r *mutationResolver) FulfillEvidence(ctx context.Context, input types.FulfillEvidenceInput) (*types.FulfillEvidencePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.EvidenceID.TenantID())
|
|
|
|
req := probo.FulfilledEvidenceRequest{
|
|
EvidenceID: input.EvidenceID,
|
|
}
|
|
|
|
if input.File != nil {
|
|
req.File = input.File.File
|
|
req.Filename = &input.File.Filename
|
|
}
|
|
|
|
if input.URL != nil {
|
|
req.URL = input.URL
|
|
}
|
|
|
|
evidence, err := svc.Evidences.Fulfill(ctx, req)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot fulfill evidence: %w", err))
|
|
}
|
|
|
|
return &types.FulfillEvidencePayload{
|
|
EvidenceEdge: types.NewEvidenceEdge(evidence, coredata.EvidenceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// CreateEvidence is the resolver for the createEvidence field.
|
|
func (r *mutationResolver) CreateEvidence(ctx context.Context, input types.CreateEvidenceInput) (*types.CreateEvidencePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.TaskID.TenantID())
|
|
|
|
req := probo.CreateEvidenceRequest{
|
|
TaskID: input.TaskID,
|
|
Name: input.Name,
|
|
Type: input.Type,
|
|
Description: input.Description,
|
|
}
|
|
|
|
if input.Type == coredata.EvidenceTypeFile {
|
|
if input.File == nil {
|
|
return nil, fmt.Errorf("file is required for FILE type evidence")
|
|
}
|
|
req.File = input.File.File
|
|
} else if input.Type == coredata.EvidenceTypeLink {
|
|
if input.URL == nil || *input.URL == "" {
|
|
return nil, fmt.Errorf("URL is required for LINK type evidence")
|
|
}
|
|
}
|
|
|
|
evidence, err := svc.Evidences.Create(ctx, req)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to create evidence: %w", err))
|
|
}
|
|
|
|
return &types.CreateEvidencePayload{
|
|
EvidenceEdge: types.NewEvidenceEdge(evidence, coredata.EvidenceOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteEvidence is the resolver for the deleteEvidence field.
|
|
func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.EvidenceID.TenantID())
|
|
|
|
err := svc.Evidences.Delete(ctx, input.EvidenceID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to delete evidence: %w", err))
|
|
}
|
|
|
|
return &types.DeleteEvidencePayload{
|
|
DeletedEvidenceID: input.EvidenceID,
|
|
}, nil
|
|
}
|
|
|
|
// UploadVendorComplianceReport is the resolver for the uploadVendorComplianceReport field.
|
|
func (r *mutationResolver) UploadVendorComplianceReport(ctx context.Context, input types.UploadVendorComplianceReportInput) (*types.UploadVendorComplianceReportPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID())
|
|
|
|
vendorComplianceReport, err := svc.VendorComplianceReports.Upload(
|
|
ctx,
|
|
input.VendorID,
|
|
&probo.VendorComplianceReportCreateRequest{
|
|
File: input.File.File,
|
|
ReportDate: input.ReportDate,
|
|
ValidUntil: input.ValidUntil,
|
|
ReportName: input.ReportName,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to upload vendor compliance report: %w", err))
|
|
}
|
|
|
|
return &types.UploadVendorComplianceReportPayload{
|
|
VendorComplianceReportEdge: types.NewVendorComplianceReportEdge(vendorComplianceReport, coredata.VendorComplianceReportOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeleteVendorComplianceReport is the resolver for the deleteVendorComplianceReport field.
|
|
func (r *mutationResolver) DeleteVendorComplianceReport(ctx context.Context, input types.DeleteVendorComplianceReportInput) (*types.DeleteVendorComplianceReportPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.ReportID.TenantID())
|
|
|
|
err := svc.VendorComplianceReports.Delete(ctx, input.ReportID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to delete vendor compliance report: %w", err))
|
|
}
|
|
|
|
return &types.DeleteVendorComplianceReportPayload{
|
|
DeletedVendorComplianceReportID: input.ReportID,
|
|
}, nil
|
|
}
|
|
|
|
// CreatePolicy is the resolver for the createPolicy field.
|
|
func (r *mutationResolver) CreatePolicy(ctx context.Context, input types.CreatePolicyInput) (*types.CreatePolicyPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.OrganizationID.TenantID())
|
|
|
|
user := UserFromContext(ctx)
|
|
people, err := svc.Peoples.GetByUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
policy, policyVersion, err := svc.Policies.Create(
|
|
ctx,
|
|
probo.CreatePolicyRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
Title: input.Title,
|
|
OwnerID: input.OwnerID,
|
|
Content: input.Content,
|
|
CreatedBy: people.ID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create policy: %w", err))
|
|
}
|
|
|
|
return &types.CreatePolicyPayload{
|
|
PolicyEdge: types.NewPolicyEdge(policy, coredata.PolicyOrderFieldTitle),
|
|
PolicyVersionEdge: types.NewPolicyVersionEdge(policyVersion, coredata.PolicyVersionOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// DeletePolicy is the resolver for the deletePolicy field.
|
|
func (r *mutationResolver) DeletePolicy(ctx context.Context, input types.DeletePolicyInput) (*types.DeletePolicyPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyID.TenantID())
|
|
|
|
err := svc.Policies.Delete(ctx, input.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot delete policy: %w", err))
|
|
}
|
|
|
|
return &types.DeletePolicyPayload{
|
|
DeletedPolicyID: input.PolicyID,
|
|
}, nil
|
|
}
|
|
|
|
// PublishPolicyVersion is the resolver for the publishPolicyVersion field.
|
|
func (r *mutationResolver) PublishPolicyVersion(ctx context.Context, input types.PublishPolicyVersionInput) (*types.PublishPolicyVersionPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyID.TenantID())
|
|
user := UserFromContext(ctx)
|
|
|
|
people, err := svc.Peoples.GetByUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
policy, policyVersion, err := svc.Policies.PublishVersion(ctx, input.PolicyID, people.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot publish policy version: %w", err))
|
|
}
|
|
|
|
return &types.PublishPolicyVersionPayload{
|
|
PolicyVersion: types.NewPolicyVersion(policyVersion),
|
|
Policy: types.NewPolicy(policy),
|
|
}, nil
|
|
}
|
|
|
|
// CreateDraftPolicyVersion is the resolver for the createDraftPolicyVersion field.
|
|
func (r *mutationResolver) CreateDraftPolicyVersion(ctx context.Context, input types.CreateDraftPolicyVersionInput) (*types.CreateDraftPolicyVersionPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyID.TenantID())
|
|
|
|
user := UserFromContext(ctx)
|
|
people, err := svc.Peoples.GetByUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
policyVersion, err := svc.Policies.CreateDraft(ctx, input.PolicyID, people.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create draft policy version: %w", err))
|
|
}
|
|
|
|
return &types.CreateDraftPolicyVersionPayload{
|
|
PolicyVersionEdge: types.NewPolicyVersionEdge(policyVersion, coredata.PolicyVersionOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// UpdatePolicyVersion is the resolver for the updatePolicyVersion field.
|
|
func (r *mutationResolver) UpdatePolicyVersion(ctx context.Context, input types.UpdatePolicyVersionInput) (*types.UpdatePolicyVersionPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyVersionID.TenantID())
|
|
|
|
policyVersion, err := svc.Policies.UpdateVersion(ctx, probo.UpdatePolicyVersionRequest{
|
|
ID: input.PolicyVersionID,
|
|
Content: input.Content,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot update policy version: %w", err))
|
|
}
|
|
|
|
return &types.UpdatePolicyVersionPayload{
|
|
PolicyVersion: types.NewPolicyVersion(policyVersion),
|
|
}, nil
|
|
}
|
|
|
|
// RequestSignature is the resolver for the requestSignature field.
|
|
func (r *mutationResolver) RequestSignature(ctx context.Context, input types.RequestSignatureInput) (*types.RequestSignaturePayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.PolicyVersionID.TenantID())
|
|
|
|
user := UserFromContext(ctx)
|
|
|
|
people, err := svc.Peoples.GetByUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
policyVersionSignature, err := svc.Policies.RequestSignature(
|
|
ctx,
|
|
probo.RequestSignatureRequest{
|
|
PolicyVersionID: input.PolicyVersionID,
|
|
RequestedBy: people.ID,
|
|
Signatory: input.SignatoryID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot request signature: %w", err))
|
|
}
|
|
|
|
return &types.RequestSignaturePayload{
|
|
PolicyVersionSignatureEdge: types.NewPolicyVersionSignatureEdge(policyVersionSignature, coredata.PolicyVersionSignatureOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field.
|
|
func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID())
|
|
|
|
vendorRiskAssessment, err := svc.Vendors.CreateRiskAssessment(
|
|
ctx,
|
|
probo.CreateVendorRiskAssessmentRequest{
|
|
VendorID: input.VendorID,
|
|
AssessedByID: input.AssessedBy,
|
|
ExpiresAt: input.ExpiresAt,
|
|
DataSensitivity: input.DataSensitivity,
|
|
BusinessImpact: input.BusinessImpact,
|
|
Notes: input.Notes,
|
|
},
|
|
)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot create vendor risk assessment: %w", err))
|
|
}
|
|
|
|
return &types.CreateVendorRiskAssessmentPayload{
|
|
VendorRiskAssessmentEdge: types.NewVendorRiskAssessmentEdge(vendorRiskAssessment, coredata.VendorRiskAssessmentOrderFieldCreatedAt),
|
|
}, nil
|
|
}
|
|
|
|
// LogoURL is the resolver for the logoUrl field.
|
|
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
return svc.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
|
|
}
|
|
|
|
// Users is the resolver for the users field.
|
|
func (r *organizationResolver) Users(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.UserOrderBy) (*types.UserConnection, error) {
|
|
pageOrderBy := page.OrderBy[coredata.UserOrderField]{
|
|
Field: coredata.UserOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.UserOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := r.usrmgrSvc.ListUsersForTenant(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list users: %w", err))
|
|
}
|
|
|
|
return types.NewUserConnection(page), nil
|
|
}
|
|
|
|
// Connectors is the resolver for the connectors field.
|
|
func (r *organizationResolver) Connectors(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ConnectorOrder) (*types.ConnectorConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.ConnectorOrderField]{
|
|
Field: coredata.ConnectorOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.ConnectorOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Connectors.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization connectors: %w", err))
|
|
}
|
|
|
|
return types.NewConnectorConnection(page), 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) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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 := svc.Frameworks.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization frameworks: %w", err))
|
|
}
|
|
|
|
return types.NewFrameworkConnection(page), 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) (*types.VendorConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Vendors.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization vendors: %w", err))
|
|
}
|
|
|
|
return types.NewVendorConnection(page), nil
|
|
}
|
|
|
|
// Peoples is the resolver for the peoples field.
|
|
func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy) (*types.PeopleConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PeopleOrderField]{
|
|
Field: coredata.PeopleOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PeopleOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Peoples.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization peoples: %w", err))
|
|
}
|
|
|
|
return types.NewPeopleConnection(page), nil
|
|
}
|
|
|
|
// Policies is the resolver for the policies field.
|
|
func (r *organizationResolver) Policies(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyOrderBy) (*types.PolicyConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: coredata.PolicyOrderFieldTitle,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Policies.ListByOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization policies: %w", err))
|
|
}
|
|
|
|
return types.NewPolicyConnection(page), nil
|
|
}
|
|
|
|
// Mesures is the resolver for the mesures field.
|
|
func (r *organizationResolver) Mesures(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MesureOrderBy) (*types.MesureConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MesureOrderField]{
|
|
Field: coredata.MesureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MesureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Mesures.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization mesures: %w", err))
|
|
}
|
|
|
|
return types.NewMesureConnection(page), 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) (*types.RiskConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Risks.ListForOrganizationID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list organization risks: %w", err))
|
|
}
|
|
|
|
return types.NewRiskConnection(page), nil
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policy, err := svc.Policies.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy: %w", err))
|
|
}
|
|
|
|
// Get the owner
|
|
owner, err := svc.Peoples.Get(ctx, policy.OwnerID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get owner: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(owner), nil
|
|
}
|
|
|
|
// Versions is the resolver for the versions field.
|
|
func (r *policyResolver) Versions(ctx context.Context, obj *types.Policy, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyVersionOrderBy, filter *types.PolicyVersionFilter) (*types.PolicyVersionConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PolicyVersionOrderField]{
|
|
Field: coredata.PolicyVersionOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PolicyVersionOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Policies.ListVersions(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list policy versions: %w", err))
|
|
}
|
|
|
|
return types.NewPolicyVersionConnection(page), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *policyResolver) Controls(ctx context.Context, obj *types.Policy, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Controls.ListForPolicyID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list policy controls: %w", err))
|
|
}
|
|
|
|
return types.NewControlConnection(page), nil
|
|
}
|
|
|
|
// Policy is the resolver for the policy field.
|
|
func (r *policyVersionResolver) Policy(ctx context.Context, obj *types.PolicyVersion) (*types.Policy, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policyVersion, err := svc.Policies.GetVersion(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version: %w", err))
|
|
}
|
|
|
|
policy, err := svc.Policies.Get(ctx, policyVersion.PolicyID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy: %w", err))
|
|
}
|
|
|
|
return types.NewPolicy(policy), nil
|
|
}
|
|
|
|
// Signatures is the resolver for the signatures field.
|
|
func (r *policyVersionResolver) Signatures(ctx context.Context, obj *types.PolicyVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyVersionSignatureOrder) (*types.PolicyVersionSignatureConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PolicyVersionSignatureOrderField]{
|
|
Field: coredata.PolicyVersionSignatureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PolicyVersionSignatureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Policies.ListSignatures(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list policy version signatures: %w", err))
|
|
}
|
|
|
|
return types.NewPolicyVersionSignatureConnection(page), nil
|
|
}
|
|
|
|
// PublishedBy is the resolver for the publishedBy field.
|
|
func (r *policyVersionResolver) PublishedBy(ctx context.Context, obj *types.PolicyVersion) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policyVersion, err := svc.Policies.GetVersion(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version: %w", err))
|
|
}
|
|
|
|
if policyVersion.PublishedBy == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, *policyVersion.PublishedBy)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// PolicyVersion is the resolver for the policyVersion field.
|
|
func (r *policyVersionSignatureResolver) PolicyVersion(ctx context.Context, obj *types.PolicyVersionSignature) (*types.PolicyVersion, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policyVersionSignature, err := svc.Policies.GetVersionSignature(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version signature: %w", err))
|
|
}
|
|
|
|
policyVersion, err := svc.Policies.GetVersion(ctx, policyVersionSignature.PolicyVersionID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version: %w", err))
|
|
}
|
|
|
|
return types.NewPolicyVersion(policyVersion), nil
|
|
}
|
|
|
|
// SignedBy is the resolver for the signedBy field.
|
|
func (r *policyVersionSignatureResolver) SignedBy(ctx context.Context, obj *types.PolicyVersionSignature) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policyVersionSignature, err := svc.Policies.GetVersionSignature(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version signature: %w", err))
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, policyVersionSignature.SignedBy)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// RequestedBy is the resolver for the requestedBy field.
|
|
func (r *policyVersionSignatureResolver) RequestedBy(ctx context.Context, obj *types.PolicyVersionSignature) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
policyVersionSignature, err := svc.Policies.GetVersionSignature(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version signature: %w", err))
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, policyVersionSignature.RequestedBy)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// Node is the resolver for the node field.
|
|
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, id.TenantID())
|
|
|
|
switch id.EntityType() {
|
|
case coredata.OrganizationEntityType:
|
|
organization, err := svc.Organizations.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get organization: %w", err))
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
case coredata.PeopleEntityType:
|
|
people, err := svc.Peoples.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get people: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
case coredata.VendorEntityType:
|
|
vendor, err := svc.Vendors.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get vendor: %w", err))
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
case coredata.FrameworkEntityType:
|
|
framework, err := svc.Frameworks.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get framework: %w", err))
|
|
}
|
|
|
|
return types.NewFramework(framework), nil
|
|
case coredata.MesureEntityType:
|
|
mesure, err := svc.Mesures.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get mesure: %w", err))
|
|
}
|
|
|
|
return types.NewMesure(mesure), nil
|
|
case coredata.TaskEntityType:
|
|
task, err := svc.Tasks.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get task: %w", err))
|
|
}
|
|
|
|
return types.NewTask(task), nil
|
|
case coredata.EvidenceEntityType:
|
|
evidence, err := svc.Evidences.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get evidence: %w", err))
|
|
}
|
|
|
|
return types.NewEvidence(evidence), nil
|
|
case coredata.PolicyEntityType:
|
|
policy, err := svc.Policies.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy: %w", err))
|
|
}
|
|
return types.NewPolicy(policy), nil
|
|
case coredata.ControlEntityType:
|
|
control, err := svc.Controls.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get control: %w", err))
|
|
}
|
|
|
|
return types.NewControl(control), nil
|
|
case coredata.RiskEntityType:
|
|
risk, err := svc.Risks.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get risk: %w", err))
|
|
}
|
|
return types.NewRisk(risk), nil
|
|
case coredata.VendorComplianceReportEntityType:
|
|
vendorComplianceReport, err := svc.VendorComplianceReports.Get(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get vendor compliance report: %w", err))
|
|
}
|
|
return types.NewVendorComplianceReport(vendorComplianceReport), nil
|
|
case coredata.PolicyVersionEntityType:
|
|
policyVersion, err := svc.Policies.GetVersion(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version: %w", err))
|
|
}
|
|
return types.NewPolicyVersion(policyVersion), nil
|
|
case coredata.PolicyVersionSignatureEntityType:
|
|
policyVersionSignature, err := svc.Policies.GetVersionSignature(ctx, id)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get policy version signature: %w", err))
|
|
}
|
|
return types.NewPolicyVersionSignature(policyVersionSignature), nil
|
|
default:
|
|
}
|
|
|
|
return nil, gqlerror.Errorf("node %q not found", id)
|
|
}
|
|
|
|
// Viewer is the resolver for the viewer field.
|
|
func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
|
|
user := UserFromContext(ctx)
|
|
session := SessionFromContext(ctx)
|
|
|
|
return &types.Viewer{
|
|
ID: session.ID,
|
|
User: types.NewUser(user),
|
|
}, nil
|
|
}
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
risk, err := svc.Risks.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get risk: %w", err))
|
|
}
|
|
|
|
if risk.OwnerID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
owner, err := svc.Peoples.Get(ctx, *risk.OwnerID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get owner: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(owner), nil
|
|
}
|
|
|
|
// Mesures is the resolver for the mesures field.
|
|
func (r *riskResolver) Mesures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MesureOrderBy) (*types.MesureConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.MesureOrderField]{
|
|
Field: coredata.MesureOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.MesureOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Mesures.ListForRiskID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list risk mesures: %w", err))
|
|
}
|
|
|
|
return types.NewMesureConnection(page), nil
|
|
}
|
|
|
|
// Policies is the resolver for the policies field.
|
|
func (r *riskResolver) Policies(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyOrderBy) (*types.PolicyConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: coredata.PolicyOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.PolicyOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Policies.ListForRiskID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list risk policies: %w", err))
|
|
}
|
|
|
|
return types.NewPolicyConnection(page), nil
|
|
}
|
|
|
|
// Controls is the resolver for the controls field.
|
|
func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, 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)
|
|
|
|
page, err := svc.Controls.ListForRiskID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot list risk controls: %w", err))
|
|
}
|
|
|
|
return types.NewControlConnection(page), nil
|
|
}
|
|
|
|
// AssignedTo is the resolver for the assignedTo field.
|
|
func (r *taskResolver) AssignedTo(ctx context.Context, obj *types.Task) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
task, err := svc.Tasks.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get task: %w", err))
|
|
}
|
|
|
|
if task.AssignedToID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, *task.AssignedToID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot get assigned to: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// Evidences is the resolver for the evidences field.
|
|
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: coredata.EvidenceOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.EvidenceOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
page, err := svc.Evidences.ListForTaskID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list task evidences: %w", err))
|
|
}
|
|
|
|
return types.NewEvidenceConnection(page), nil
|
|
}
|
|
|
|
// People is the resolver for the people field.
|
|
func (r *userResolver) People(ctx context.Context, obj *types.User, organizationID gid.GID) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, organizationID.TenantID())
|
|
|
|
people, err := svc.Peoples.GetByUserID(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get people: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// ComplianceReports is the resolver for the complianceReports field.
|
|
func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorComplianceReportOrderField]{
|
|
Field: coredata.VendorComplianceReportOrderFieldReportDate,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorComplianceReportOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.VendorComplianceReports.ListForVendorID(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list vendor compliance reports: %w", err))
|
|
}
|
|
|
|
return types.NewVendorComplianceReportConnection(page), nil
|
|
}
|
|
|
|
// RiskAssessments is the resolver for the riskAssessments field.
|
|
func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
pageOrderBy := page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
|
|
Field: coredata.VendorRiskAssessmentOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
page, err := svc.Vendors.ListRiskAssessments(ctx, obj.ID, cursor)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list vendor risk assessments: %w", err))
|
|
}
|
|
|
|
return types.NewVendorRiskAssessmentConnection(page), nil
|
|
}
|
|
|
|
// BusinessOwner is the resolver for the businessOwner field.
|
|
func (r *vendorResolver) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get vendor: %w", err))
|
|
}
|
|
|
|
if vendor.BusinessOwnerID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, *vendor.BusinessOwnerID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get business owner: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// SecurityOwner is the resolver for the securityOwner field.
|
|
func (r *vendorResolver) SecurityOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get vendor: %w", err))
|
|
}
|
|
|
|
if vendor.SecurityOwnerID == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, *vendor.SecurityOwnerID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get security owner: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorComplianceReportResolver) Vendor(ctx context.Context, obj *types.VendorComplianceReport) (*types.Vendor, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get vendor: %w", err))
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// FileURL is the resolver for the fileUrl field.
|
|
func (r *vendorComplianceReportResolver) FileURL(ctx context.Context, obj *types.VendorComplianceReport) (string, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
fileURL, err := svc.VendorComplianceReports.GenerateFileURL(ctx, obj.ID, 1*time.Hour)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to generate file URL: %w", err))
|
|
}
|
|
|
|
return fileURL, nil
|
|
}
|
|
|
|
// Vendor is the resolver for the vendor field.
|
|
func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
vendor, err := svc.Vendors.Get(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get vendor: %w", err))
|
|
}
|
|
|
|
return types.NewVendor(vendor), nil
|
|
}
|
|
|
|
// AssessedBy is the resolver for the assessedBy field.
|
|
func (r *vendorRiskAssessmentResolver) AssessedBy(ctx context.Context, obj *types.VendorRiskAssessment) (*types.People, error) {
|
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
|
|
|
vendorRiskAssessment, err := svc.Vendors.GetRiskAssessment(ctx, obj.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get vendor risk assessment: %w", err))
|
|
}
|
|
|
|
people, err := svc.Peoples.Get(ctx, vendorRiskAssessment.AssessedBy)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get assessed by: %w", err))
|
|
}
|
|
|
|
return types.NewPeople(people), nil
|
|
}
|
|
|
|
// Organizations is the resolver for the organizations field.
|
|
func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder) (*types.OrganizationConnection, error) {
|
|
user := UserFromContext(ctx)
|
|
|
|
// For now, we're not using cursor pagination since we're loading all organizations
|
|
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to list organizations for user: %w", err))
|
|
}
|
|
|
|
var edges []*types.OrganizationEdge
|
|
for _, organization := range organizations {
|
|
edges = append(edges, types.NewOrganizationEdge(organization, coredata.OrganizationOrderFieldCreatedAt))
|
|
}
|
|
|
|
// The simple implementation doesn't handle pagination yet
|
|
return &types.OrganizationConnection{
|
|
Edges: edges,
|
|
PageInfo: &types.PageInfo{
|
|
HasNextPage: false,
|
|
HasPreviousPage: false,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// Control returns schema.ControlResolver implementation.
|
|
func (r *Resolver) Control() schema.ControlResolver { return &controlResolver{r} }
|
|
|
|
// Evidence returns schema.EvidenceResolver implementation.
|
|
func (r *Resolver) Evidence() schema.EvidenceResolver { return &evidenceResolver{r} }
|
|
|
|
// Framework returns schema.FrameworkResolver implementation.
|
|
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
|
|
|
|
// Mesure returns schema.MesureResolver implementation.
|
|
func (r *Resolver) Mesure() schema.MesureResolver { return &mesureResolver{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} }
|
|
|
|
// Policy returns schema.PolicyResolver implementation.
|
|
func (r *Resolver) Policy() schema.PolicyResolver { return &policyResolver{r} }
|
|
|
|
// PolicyVersion returns schema.PolicyVersionResolver implementation.
|
|
func (r *Resolver) PolicyVersion() schema.PolicyVersionResolver { return &policyVersionResolver{r} }
|
|
|
|
// PolicyVersionSignature returns schema.PolicyVersionSignatureResolver implementation.
|
|
func (r *Resolver) PolicyVersionSignature() schema.PolicyVersionSignatureResolver {
|
|
return &policyVersionSignatureResolver{r}
|
|
}
|
|
|
|
// Query returns schema.QueryResolver implementation.
|
|
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
|
|
|
// Risk returns schema.RiskResolver implementation.
|
|
func (r *Resolver) Risk() schema.RiskResolver { return &riskResolver{r} }
|
|
|
|
// Task returns schema.TaskResolver implementation.
|
|
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
|
|
|
|
// User returns schema.UserResolver implementation.
|
|
func (r *Resolver) User() schema.UserResolver { return &userResolver{r} }
|
|
|
|
// Vendor returns schema.VendorResolver implementation.
|
|
func (r *Resolver) Vendor() schema.VendorResolver { return &vendorResolver{r} }
|
|
|
|
// VendorComplianceReport returns schema.VendorComplianceReportResolver implementation.
|
|
func (r *Resolver) VendorComplianceReport() schema.VendorComplianceReportResolver {
|
|
return &vendorComplianceReportResolver{r}
|
|
}
|
|
|
|
// VendorRiskAssessment returns schema.VendorRiskAssessmentResolver implementation.
|
|
func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver {
|
|
return &vendorRiskAssessmentResolver{r}
|
|
}
|
|
|
|
// Viewer returns schema.ViewerResolver implementation.
|
|
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
|
|
|
|
type controlResolver struct{ *Resolver }
|
|
type evidenceResolver struct{ *Resolver }
|
|
type frameworkResolver struct{ *Resolver }
|
|
type mesureResolver struct{ *Resolver }
|
|
type mutationResolver struct{ *Resolver }
|
|
type organizationResolver struct{ *Resolver }
|
|
type policyResolver struct{ *Resolver }
|
|
type policyVersionResolver struct{ *Resolver }
|
|
type policyVersionSignatureResolver struct{ *Resolver }
|
|
type queryResolver struct{ *Resolver }
|
|
type riskResolver struct{ *Resolver }
|
|
type taskResolver struct{ *Resolver }
|
|
type userResolver struct{ *Resolver }
|
|
type vendorResolver struct{ *Resolver }
|
|
type vendorComplianceReportResolver struct{ *Resolver }
|
|
type vendorRiskAssessmentResolver struct{ *Resolver }
|
|
type viewerResolver struct{ *Resolver }
|