diff --git a/pkg/trust/compliance_page_service.go b/pkg/trust/compliance_page_service.go index 21bb5031f..99260d1d1 100644 --- a/pkg/trust/compliance_page_service.go +++ b/pkg/trust/compliance_page_service.go @@ -240,7 +240,7 @@ func (s *Service) RenderRobotsTxt( } func (s *Service) fetchDocumentIDs(ctx context.Context, scope coredata.Scoper, orgID gid.GID) ([]string, error) { - var ids []string + var resourceIDs []gid.GID var cursorKey *page.CursorKey for { @@ -264,7 +264,7 @@ func (s *Service) fetchDocumentIDs(ctx context.Context, scope coredata.Scoper, o continue } - ids = append(ids, doc.ID.String()) + resourceIDs = append(resourceIDs, doc.ID) } if !result.Info.HasNext { @@ -276,7 +276,100 @@ func (s *Service) fetchDocumentIDs(ctx context.Context, scope coredata.Scoper, o cursorKey = &ck } - return ids, nil + cursorKey = nil + for { + cursor := page.NewCursor( + page.MaxCursorSize, + cursorKey, + page.Head, + page.OrderBy[coredata.TrustCenterFileOrderField]{ + Field: coredata.TrustCenterFileOrderFieldCreatedAt, + Direction: page.OrderDirectionAsc, + }, + ) + + result, err := s.TrustCenterFiles.ListForOrganizationId( + ctx, + scope, + orgID, + cursor, + coredata.NewTrustCenterFileFilter(), + ) + if err != nil { + return nil, fmt.Errorf("cannot list trust center files: %w", err) + } + + for _, file := range result.Data { + if file.TrustCenterVisibility == coredata.TrustCenterVisibilityNone { + continue + } + + resourceIDs = append(resourceIDs, file.ID) + } + + if !result.Info.HasNext { + break + } + + last := result.Data[len(result.Data)-1] + ck := last.CursorKey(coredata.TrustCenterFileOrderFieldCreatedAt) + cursorKey = &ck + } + + cursorKey = nil + for { + cursor := page.NewCursor( + page.MaxCursorSize, + cursorKey, + page.Head, + page.OrderBy[coredata.AuditOrderField]{ + Field: coredata.AuditOrderFieldCreatedAt, + Direction: page.OrderDirectionAsc, + }, + ) + + result, err := s.Audits.ListForOrganizationId(ctx, scope, orgID, cursor) + if err != nil { + return nil, fmt.Errorf("cannot list audits: %w", err) + } + + for _, audit := range result.Data { + if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityNone { + continue + } + + if audit.ReportFileID == nil { + continue + } + + resourceIDs = append(resourceIDs, *audit.ReportFileID) + } + + if !result.Info.HasNext { + break + } + + last := result.Data[len(result.Data)-1] + ck := last.CursorKey(coredata.AuditOrderFieldCreatedAt) + cursorKey = &ck + } + + aliases, err := s.TrustCenterAliases.LoadByResourceIDs(ctx, scope, resourceIDs) + if err != nil { + return nil, fmt.Errorf("cannot load trust center aliases: %w", err) + } + + paths := make([]string, 0, len(resourceIDs)) + for _, resourceID := range resourceIDs { + if alias, ok := aliases[resourceID]; ok { + paths = append(paths, alias) + continue + } + + paths = append(paths, resourceID.String()) + } + + return paths, nil } func (s *Service) fetchComplianceFrameworks(ctx context.Context, scope coredata.Scoper, trustCenterID gid.GID) ([]compliancePageFramework, error) { diff --git a/pkg/trust/service.go b/pkg/trust/service.go index b076d36be..b8fa1371b 100644 --- a/pkg/trust/service.go +++ b/pkg/trust/service.go @@ -62,6 +62,7 @@ type ( Reports *ReportService Organizations *OrganizationService ComplianceExternalURLs *ComplianceExternalURLService + TrustCenterAliases *TrustCenterAliasService } ) @@ -103,6 +104,7 @@ func NewService( svc.Reports = &ReportService{svc: svc} svc.Organizations = &OrganizationService{svc: svc} svc.ComplianceExternalURLs = &ComplianceExternalURLService{svc: svc} + svc.TrustCenterAliases = &TrustCenterAliasService{svc: svc} return svc } diff --git a/pkg/trust/trust_center_alias_service.go b/pkg/trust/trust_center_alias_service.go new file mode 100644 index 000000000..2b64b95eb --- /dev/null +++ b/pkg/trust/trust_center_alias_service.go @@ -0,0 +1,115 @@ +// Copyright (c) 2025-2026 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package trust + +import ( + "context" + "errors" + "fmt" + + "go.gearno.de/kit/pg" + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/gid" +) + +type TrustCenterAliasService struct { + svc *Service +} + +func (s TrustCenterAliasService) ResolveAlias( + ctx context.Context, + scope coredata.Scoper, + organizationID gid.GID, + alias string, +) (gid.GID, error) { + record := &coredata.TrustCenterAlias{} + + err := s.svc.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := record.LoadByAlias(ctx, conn, scope, organizationID, alias); err != nil { + return fmt.Errorf("cannot load trust center alias: %w", err) + } + + return nil + }, + ) + if err != nil { + return gid.Nil, err + } + + return record.ResourceID, nil +} + +func (s TrustCenterAliasService) GetByStorageResourceID( + ctx context.Context, + scope coredata.Scoper, + storageResourceID gid.GID, +) (*string, error) { + record := &coredata.TrustCenterAlias{} + + err := s.svc.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := record.LoadByResourceID(ctx, conn, scope, storageResourceID); err != nil { + return fmt.Errorf("cannot load trust center alias: %w", err) + } + + return nil + }, + ) + if err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + return nil, nil + } + + return nil, err + } + + return &record.Alias, nil +} + +func (s TrustCenterAliasService) LoadByResourceIDs( + ctx context.Context, + scope coredata.Scoper, + resourceIDs []gid.GID, +) (map[gid.GID]string, error) { + if len(resourceIDs) == 0 { + return map[gid.GID]string{}, nil + } + + var aliases coredata.TrustCenterAliases + + err := s.svc.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := aliases.LoadByResourceIDs(ctx, conn, scope, resourceIDs); err != nil { + return fmt.Errorf("cannot load trust center aliases: %w", err) + } + + return nil + }, + ) + if err != nil { + return nil, err + } + + result := make(map[gid.GID]string, len(aliases)) + for _, alias := range aliases { + result[alias.ResourceID] = alias.Alias + } + + return result, nil +}