Files
probo/pkg/server/api/trust/v1/base_resolvers.go
Émile Ré 622f1ba67d Address PR review on data request pages
Require a verified viewer email before creating a rights request and
validate the free-text fields with the same SafeText bounds the console
uses, so this public portal mutation stays safe and bounded.

Move myRightsRequests onto the base Query, drop the now-dead count
loaders, and order the RECTIFICATION enum value before PORTABILITY so
the Postgres sort order matches RightsRequestTypes().

Harden the v2 kit primitives: SegmentedControl keeps equal-width cards
(auto-fill), preserves its selection when the active card is toggled,
and forwards an accessible name; Field associates its label and error
by id/aria instead of wrapping the control in a label. Give the type
group an accessible name, require the name field for non-complaint
types, use a timezone-stable reference year, drop the underreporting
header count, and neutralize the response-deadline copy.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-20 14:31:42 +02:00

350 lines
11 KiB
Go

package trust_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.93
import (
"context"
"errors"
"strings"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/mailman"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/compliancepage"
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/trust"
)
// Viewer is the resolver for the viewer field.
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, nil
}
return &types.Identity{
ID: identity.ID,
Email: identity.EmailAddress,
FullName: identity.FullName,
EmailVerified: identity.EmailAddressVerified,
CreatedAt: identity.CreatedAt,
UpdatedAt: identity.UpdatedAt,
}, nil
}
// Node is the resolver for the node field.
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
trustService := r.trust
switch id.EntityType() {
case coredata.OrganizationEntityType:
organization, err := trustService.Organizations.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewOrganization(organization), nil
case coredata.DocumentEntityType:
document, err := trustService.Documents.Get(ctx, scope, compliancePage.OrganizationID, id)
if err != nil {
if errors.Is(err, trust.ErrDocumentNotFound) || errors.Is(err, trust.ErrDocumentNotVisible) || errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
if _, ok := errors.AsType[*trust.ErrDocumentArchived](err); ok {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get document", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewDocument(document), nil
case coredata.FrameworkEntityType:
framework, err := trustService.Frameworks.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get framework", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewFramework(framework), nil
case coredata.FileEntityType:
file, err := trustService.Reports.Get(ctx, scope, compliancePage.OrganizationID, id)
if err != nil {
if errors.Is(err, trust.ErrReportNotFound) || errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get audit report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
audit, err := trustService.Audits.GetByReportFileID(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get audit for report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityNone {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
return types.NewAuditReport(file), nil
case coredata.AuditEntityType:
audit, err := trustService.Audits.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get audit", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityNone {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
return types.NewAudit(audit), nil
case coredata.ThirdPartyEntityType:
thirdParty, err := trustService.ThirdParties.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get thirdParty", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if !thirdParty.ShowOnTrustCenter {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
return types.NewSubprocessor(thirdParty), nil
case coredata.TrustCenterEntityType:
trustCenter, err := trustService.TrustCenters.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewTrustCenter(trustCenter), nil
case coredata.TrustCenterReferenceEntityType:
reference, err := trustService.TrustCenterReferences.Get(ctx, scope, id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get trust center reference", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewTrustCenterReference(reference), nil
case coredata.TrustCenterFileEntityType:
trustCenterFile, err := trustService.TrustCenterFiles.Get(ctx, scope, compliancePage.OrganizationID, id)
if err != nil {
if errors.Is(err, trust.ErrTrustCenterFileNotFound) || errors.Is(err, trust.ErrTrustCenterFileNotVisible) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get trust center file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewTrustCenterFile(trustCenterFile), nil
case coredata.MailingListUpdateEntityType:
update, err := r.mailman.GetMailingListUpdate(ctx, id)
if err != nil {
if errors.Is(err, mailman.ErrMailingListUpdateNotFound) || errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get mailing list update", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if update.Status != coredata.MailingListUpdateStatusSent {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
trustCenter, err := trustService.TrustCenters.Get(ctx, scope, compliancePage.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if trustCenter.MailingListID == nil || *trustCenter.MailingListID != update.MailingListID {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
return types.NewMailingListUpdate(update), nil
default:
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
}
// AliasedNode is the resolver for the aliasedNode field.
func (r *queryResolver) AliasedNode(ctx context.Context, alias string) (types.Node, error) {
resourceID, err := gid.ParseGID(alias)
if err != nil {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
resourceID, err = r.resourceAlias.ResolveAlias(
ctx,
scope,
alias,
)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", alias)
}
r.logger.ErrorCtx(ctx, "cannot resolve resource alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
return r.Node(ctx, resourceID)
}
// CurrentTrustCenter is the resolver for the currentTrustCenter field.
func (r *queryResolver) CurrentTrustCenter(ctx context.Context) (*types.TrustCenter, error) {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
trustService := r.trust
org, err := trustService.Organizations.Get(ctx, scope, compliancePage.OrganizationID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
trustCenter, err := trustService.TrustCenters.Get(ctx, scope, compliancePage.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
response := types.NewTrustCenter(trustCenter)
response.Organization = types.NewOrganization(org)
return response, nil
}
// OidcProviders is the resolver for the oidcProviders field.
func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProviderInfo, error) {
providers := r.iam.OIDCService.EnabledProviders()
result := make([]*types.OIDCProviderInfo, 0, len(providers))
for _, p := range providers {
name := strings.ToLower(p.String())
result = append(
result,
&types.OIDCProviderInfo{
Name: name,
LoginURL: r.baseURL.WithPath("/api/connect/v1/oidc/" + name + "/login").MustString(),
},
)
}
return result, nil
}
// MyRightsRequests is the resolver for the myRightsRequests field.
func (r *queryResolver) MyRightsRequests(ctx context.Context, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.RightsRequestConnection, error) {
pageOrderBy := page.OrderBy[coredata.RightsRequestOrderField]{
Field: coredata.RightsRequestOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
identity := authn.IdentityFromContext(ctx)
if identity == nil {
emptyPage := page.NewPage([]*coredata.RightsRequest{}, cursor)
return types.NewRightsRequestConnection(emptyPage), nil
}
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
result, err := r.trust.RightsRequests.ListForOrganizationIDAndContact(
ctx,
scope,
compliancePage.OrganizationID,
identity.EmailAddress.String(),
cursor,
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list rights requests", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewRightsRequestConnection(result), nil
}
// Mutation returns schema.MutationResolver implementation.
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
// Query returns schema.QueryResolver implementation.
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
type (
mutationResolver struct{ *Resolver }
queryResolver struct{ *Resolver }
)