Rename backend services for portal
Point domain services, bootstrap, and related packages at Compliance Portal types so callers stop depending on the old Trust Center names. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
713
pkg/complianceportal/visitor/compliance_portal_service.go
Normal file
713
pkg/complianceportal/visitor/compliance_portal_service.go
Normal file
@@ -0,0 +1,713 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package visitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"go.gearno.de/x/ref"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
//go:embed compliance.md.tmpl
|
||||
var complianceTmplContent string
|
||||
|
||||
//go:embed sitemap.xml.tmpl
|
||||
var sitemapTmplContent string
|
||||
|
||||
//go:embed robots.txt.tmpl
|
||||
var robotsTmplContent string
|
||||
|
||||
var complianceTmpl = template.Must(
|
||||
template.New("compliance").
|
||||
Funcs(template.FuncMap{
|
||||
"cell": func(s string) string {
|
||||
s = strings.ReplaceAll(s, `|`, `\|`)
|
||||
s = strings.ReplaceAll(s, "\n", " ")
|
||||
s = strings.ReplaceAll(s, "\r", "")
|
||||
|
||||
return s
|
||||
},
|
||||
}).
|
||||
Parse(complianceTmplContent),
|
||||
)
|
||||
|
||||
var sitemapTmpl = template.Must(
|
||||
template.New("sitemap").Parse(sitemapTmplContent),
|
||||
)
|
||||
|
||||
var robotsTmpl = template.Must(
|
||||
template.New("robots").Parse(robotsTmplContent),
|
||||
)
|
||||
|
||||
type (
|
||||
compliancePageData struct {
|
||||
OrgName string
|
||||
Description string
|
||||
Details []compliancePageDetail
|
||||
Frameworks []compliancePageFramework
|
||||
Documents []compliancePageDocument
|
||||
Audits []compliancePageAudit
|
||||
ThirdParties []compliancePageThirdParty
|
||||
References []compliancePageReference
|
||||
CustomLinks []compliancePageCustomLink
|
||||
}
|
||||
|
||||
compliancePageDetail struct {
|
||||
Label string
|
||||
Value string
|
||||
}
|
||||
|
||||
compliancePageFramework struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
compliancePageDocument struct {
|
||||
Title string
|
||||
Type string
|
||||
}
|
||||
|
||||
compliancePageAudit struct {
|
||||
Name string
|
||||
Framework string
|
||||
ValidFrom string
|
||||
ValidUntil string
|
||||
}
|
||||
|
||||
compliancePageThirdParty struct {
|
||||
Name string
|
||||
Category string
|
||||
Countries string
|
||||
Website string
|
||||
}
|
||||
|
||||
compliancePageReference struct {
|
||||
Name string
|
||||
Description string
|
||||
Website string
|
||||
}
|
||||
|
||||
compliancePageCustomLink struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
)
|
||||
|
||||
func (s *Service) RenderCompliancePortalMarkdown(
|
||||
ctx context.Context,
|
||||
w io.Writer,
|
||||
compliancePageID gid.GID,
|
||||
scope coredata.Scoper,
|
||||
) error {
|
||||
org, err := s.GetPortalOrganization(ctx, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load organization for compliance page: %w", err)
|
||||
}
|
||||
|
||||
compliancePage, err := s.GetPortalByID(ctx, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load compliance page: %w", err)
|
||||
}
|
||||
|
||||
data := &compliancePageData{
|
||||
OrgName: org.Name,
|
||||
}
|
||||
|
||||
if compliancePage.Description != nil && *compliancePage.Description != "" {
|
||||
data.Description = *compliancePage.Description
|
||||
}
|
||||
|
||||
if compliancePage.WebsiteURL != nil && *compliancePage.WebsiteURL != "" {
|
||||
data.Details = append(data.Details, compliancePageDetail{Label: "Website", Value: *compliancePage.WebsiteURL})
|
||||
}
|
||||
|
||||
if compliancePage.Email != nil && *compliancePage.Email != "" {
|
||||
data.Details = append(data.Details, compliancePageDetail{Label: "Email", Value: *compliancePage.Email})
|
||||
}
|
||||
|
||||
if compliancePage.HeadquarterAddress != nil && *compliancePage.HeadquarterAddress != "" {
|
||||
data.Details = append(data.Details, compliancePageDetail{Label: "Headquarters", Value: *compliancePage.HeadquarterAddress})
|
||||
}
|
||||
|
||||
data.Frameworks, err = s.fetchComplianceFrameworks(ctx, scope, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch compliance frameworks: %w", err)
|
||||
}
|
||||
|
||||
data.Documents, err = s.fetchDocuments(ctx, scope, org.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch documents: %w", err)
|
||||
}
|
||||
|
||||
data.Audits, err = s.fetchAudits(ctx, scope, org.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch audits: %w", err)
|
||||
}
|
||||
|
||||
data.ThirdParties, err = s.fetchThirdParties(ctx, scope, org.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch thirdParties: %w", err)
|
||||
}
|
||||
|
||||
data.References, err = s.fetchReferences(ctx, scope, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch references: %w", err)
|
||||
}
|
||||
|
||||
data.CustomLinks, err = s.fetchCustomLinks(ctx, scope, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch external links: %w", err)
|
||||
}
|
||||
|
||||
if err := complianceTmpl.Execute(w, data); err != nil {
|
||||
return fmt.Errorf("cannot render compliance page markdown: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type (
|
||||
sitemapData struct {
|
||||
BaseURL string
|
||||
Documents []string
|
||||
}
|
||||
|
||||
robotsData struct {
|
||||
Indexable bool
|
||||
BaseURL string
|
||||
}
|
||||
)
|
||||
|
||||
func (s *Service) RenderSitemap(
|
||||
ctx context.Context,
|
||||
w io.Writer,
|
||||
compliancePageID gid.GID,
|
||||
scope coredata.Scoper,
|
||||
baseURL string,
|
||||
) error {
|
||||
org, err := s.GetPortalOrganization(ctx, compliancePageID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load organization for sitemap: %w", err)
|
||||
}
|
||||
|
||||
data := &sitemapData{
|
||||
BaseURL: baseURL,
|
||||
}
|
||||
|
||||
data.Documents, err = s.fetchDocumentIDs(ctx, scope, org.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot fetch document IDs for sitemap: %w", err)
|
||||
}
|
||||
|
||||
if err := sitemapTmpl.Execute(w, data); err != nil {
|
||||
return fmt.Errorf("cannot render sitemap: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) RenderRobotsTxt(
|
||||
ctx context.Context,
|
||||
w io.Writer,
|
||||
searchEngineIndexing coredata.SearchEngineIndexing,
|
||||
baseURL string,
|
||||
) error {
|
||||
data := &robotsData{
|
||||
Indexable: searchEngineIndexing == coredata.SearchEngineIndexingIndexable,
|
||||
BaseURL: baseURL,
|
||||
}
|
||||
|
||||
if err := robotsTmpl.Execute(w, data); err != nil {
|
||||
return fmt.Errorf("cannot render robots.txt: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchDocumentIDs(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
orgID gid.GID,
|
||||
) ([]string, error) {
|
||||
seen := make(map[gid.GID]struct{})
|
||||
|
||||
var resourceIDs []gid.GID
|
||||
|
||||
appendResourceID := func(id gid.GID) {
|
||||
if _, ok := seen[id]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
seen[id] = struct{}{}
|
||||
resourceIDs = append(resourceIDs, id)
|
||||
}
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldTitle,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListDocumentsForOrganizationID(ctx, scope, orgID, cursor, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list documents: %w", err)
|
||||
}
|
||||
|
||||
for _, doc := range result.Data {
|
||||
if doc.CompliancePortalVisibility == coredata.CompliancePortalVisibilityNone {
|
||||
continue
|
||||
}
|
||||
|
||||
appendResourceID(doc.ID)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.DocumentOrderFieldTitle)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
cursorKey = nil
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.CompliancePortalFileOrderField]{
|
||||
Field: coredata.CompliancePortalFileOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListPortalFilesForOrganizationID(
|
||||
ctx,
|
||||
scope,
|
||||
orgID,
|
||||
cursor,
|
||||
coredata.NewCompliancePortalFileFilter(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list compliance page files: %w", err)
|
||||
}
|
||||
|
||||
for _, file := range result.Data {
|
||||
if file.CompliancePortalVisibility == coredata.CompliancePortalVisibilityNone {
|
||||
continue
|
||||
}
|
||||
|
||||
appendResourceID(file.ID)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.CompliancePortalFileOrderFieldCreatedAt)
|
||||
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.ListAuditsForOrganizationID(ctx, scope, orgID, cursor, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list audits: %w", err)
|
||||
}
|
||||
|
||||
for _, audit := range result.Data {
|
||||
if audit.CompliancePortalVisibility == coredata.CompliancePortalVisibilityNone {
|
||||
continue
|
||||
}
|
||||
|
||||
if audit.ReportFileID == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
appendResourceID(*audit.ReportFileID)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.AuditOrderFieldCreatedAt)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
aliases, err := s.resourceAlias.LoadByResourceIDs(ctx, scope, resourceIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot load resource 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,
|
||||
compliancePageID gid.GID,
|
||||
) ([]compliancePageFramework, error) {
|
||||
var frameworks []compliancePageFramework
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.ComplianceFrameworkOrderField]{
|
||||
Field: coredata.ComplianceFrameworkOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListComplianceFrameworksByPortalID(ctx, scope, compliancePageID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list compliance frameworks: %w", err)
|
||||
}
|
||||
|
||||
for _, cf := range result.Data {
|
||||
if cf.Visibility != coredata.ComplianceFrameworkVisibilityPublic {
|
||||
continue
|
||||
}
|
||||
|
||||
fw, err := s.GetFramework(ctx, scope, cf.FrameworkID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get framework %s: %w", cf.FrameworkID, err)
|
||||
}
|
||||
|
||||
fi := compliancePageFramework{Name: fw.Name}
|
||||
if fw.Description != nil {
|
||||
fi.Description = *fw.Description
|
||||
}
|
||||
|
||||
frameworks = append(frameworks, fi)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.ComplianceFrameworkOrderFieldRank)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return frameworks, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchDocuments(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
orgID gid.GID,
|
||||
) ([]compliancePageDocument, error) {
|
||||
var docs []compliancePageDocument
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldTitle,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListDocumentsForOrganizationID(ctx, scope, orgID, cursor, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list documents: %w", err)
|
||||
}
|
||||
|
||||
for _, doc := range result.Data {
|
||||
if doc.CompliancePortalVisibility == coredata.CompliancePortalVisibilityNone {
|
||||
continue
|
||||
}
|
||||
|
||||
docs = append(
|
||||
docs,
|
||||
compliancePageDocument{
|
||||
Title: doc.Title,
|
||||
Type: doc.DocumentType.String(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.DocumentOrderFieldTitle)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return docs, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchAudits(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
orgID gid.GID,
|
||||
) ([]compliancePageAudit, error) {
|
||||
var audits []compliancePageAudit
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.AuditOrderField]{
|
||||
Field: coredata.AuditOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListAuditsForOrganizationID(ctx, scope, orgID, cursor, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list audits: %w", err)
|
||||
}
|
||||
|
||||
for _, audit := range result.Data {
|
||||
if audit.CompliancePortalVisibility == coredata.CompliancePortalVisibilityNone {
|
||||
continue
|
||||
}
|
||||
|
||||
frameworkName := ""
|
||||
|
||||
fw, err := s.GetFramework(ctx, scope, audit.FrameworkID)
|
||||
if err == nil {
|
||||
frameworkName = fw.Name
|
||||
}
|
||||
|
||||
ai := compliancePageAudit{
|
||||
Name: ref.UnrefOrZero(audit.Name),
|
||||
Framework: frameworkName,
|
||||
}
|
||||
if audit.ValidFrom != nil {
|
||||
ai.ValidFrom = audit.ValidFrom.Format("2006-01-02")
|
||||
}
|
||||
|
||||
if audit.ValidUntil != nil {
|
||||
ai.ValidUntil = audit.ValidUntil.Format("2006-01-02")
|
||||
}
|
||||
|
||||
audits = append(audits, ai)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.AuditOrderFieldCreatedAt)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return audits, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchThirdParties(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
orgID gid.GID,
|
||||
) ([]compliancePageThirdParty, error) {
|
||||
var thirdParties []compliancePageThirdParty
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.ThirdPartyOrderField]{
|
||||
Field: coredata.ThirdPartyOrderFieldName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListThirdPartiesForOrganizationID(ctx, scope, orgID, cursor, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list thirdParties: %w", err)
|
||||
}
|
||||
|
||||
for _, v := range result.Data {
|
||||
var countries []string
|
||||
for _, c := range v.Countries {
|
||||
countries = append(countries, c.String())
|
||||
}
|
||||
|
||||
thirdParties = append(
|
||||
thirdParties,
|
||||
compliancePageThirdParty{
|
||||
Name: v.Name,
|
||||
Category: v.Category.String(),
|
||||
Countries: strings.Join(countries, ", "),
|
||||
Website: ref.UnrefOrZero(v.WebsiteURL),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.ThirdPartyOrderFieldName)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return thirdParties, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchReferences(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
compliancePageID gid.GID,
|
||||
) ([]compliancePageReference, error) {
|
||||
var refs []compliancePageReference
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.CompliancePortalReferenceOrderField]{
|
||||
Field: coredata.CompliancePortalReferenceOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListPortalReferencesForPortalID(ctx, scope, compliancePageID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list references: %w", err)
|
||||
}
|
||||
|
||||
for _, r := range result.Data {
|
||||
ri := compliancePageReference{
|
||||
Name: r.Name,
|
||||
Website: r.WebsiteURL,
|
||||
}
|
||||
if r.Description != nil {
|
||||
ri.Description = *r.Description
|
||||
}
|
||||
|
||||
refs = append(refs, ri)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.CompliancePortalReferenceOrderFieldRank)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return refs, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchCustomLinks(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
compliancePageID gid.GID,
|
||||
) ([]compliancePageCustomLink, error) {
|
||||
var links []compliancePageCustomLink
|
||||
|
||||
var cursorKey *page.CursorKey
|
||||
for {
|
||||
cursor := page.NewCursor(
|
||||
page.MaxCursorSize,
|
||||
cursorKey,
|
||||
page.Head,
|
||||
page.OrderBy[coredata.ComplianceCustomLinkOrderField]{
|
||||
Field: coredata.ComplianceCustomLinkOrderFieldRank,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
},
|
||||
)
|
||||
|
||||
result, err := s.ListCustomLinksForPortalID(ctx, scope, compliancePageID, cursor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot list custom links: %w", err)
|
||||
}
|
||||
|
||||
for _, l := range result.Data {
|
||||
links = append(
|
||||
links,
|
||||
compliancePageCustomLink{
|
||||
Name: l.Name,
|
||||
URL: l.URL,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if !result.Info.HasNext {
|
||||
break
|
||||
}
|
||||
|
||||
last := result.Data[len(result.Data)-1]
|
||||
ck := last.CursorKey(coredata.ComplianceCustomLinkOrderFieldRank)
|
||||
cursorKey = &ck
|
||||
}
|
||||
|
||||
return links, nil
|
||||
}
|
||||
Reference in New Issue
Block a user