diff --git a/pkg/cookiebanner/service.go b/pkg/cookiebanner/service.go index 90733f82b..d1a1f9a6f 100644 --- a/pkg/cookiebanner/service.go +++ b/pkg/cookiebanner/service.go @@ -428,7 +428,7 @@ func (s *Service) ensureDraftVersionForBanner( } var categories coredata.CookieCategories - if err := categories.LoadAllByCookieBannerID(ctx, tx, scope, bannerID); err != nil { + if err := categories.LoadConsentCategoriesByCookieBannerID(ctx, tx, scope, bannerID); err != nil { return nil, fmt.Errorf("cannot load cookie categories: %w", err) } @@ -1887,7 +1887,7 @@ func (s *Service) GetActiveBannerConfig( } var categories coredata.CookieCategories - if err := categories.LoadAllByCookieBannerID(ctx, conn, scope, banner.ID); err != nil { + if err := categories.LoadConsentCategoriesByCookieBannerID(ctx, conn, scope, banner.ID); err != nil { return fmt.Errorf("cannot load cookie categories: %w", err) } diff --git a/pkg/cookiebanner/snapshot.go b/pkg/cookiebanner/snapshot.go index 58532aee1..343346ade 100644 --- a/pkg/cookiebanner/snapshot.go +++ b/pkg/cookiebanner/snapshot.go @@ -31,7 +31,8 @@ func resolveTranslations( translations coredata.CookieBannerTranslations, categories coredata.CookieCategories, ) map[string]coredata.CookieBannerVersionSnapshotTranslation { - return buildSnapshotTranslations(translations, consentCategories(categories)) + sortConsentCategories(categories) + return buildSnapshotTranslations(translations, categories) } // snapshotsEqual reports whether two version snapshots are visitor-identical. @@ -56,23 +57,16 @@ func snapshotCategoryKindOrder(k coredata.CookieCategoryKind) int { } } -// consentCategories returns the categories that are part of the consent -// contract (everything except UNCATEGORISED), sorted in snapshot order. -// UNCATEGORISED is an admin-side inbox and never shown to visitors. -func consentCategories(categories coredata.CookieCategories) coredata.CookieCategories { - filtered := make(coredata.CookieCategories, 0, len(categories)) - for _, c := range categories { - if c.Kind != coredata.CookieCategoryKindUncategorised { - filtered = append(filtered, c) - } - } - slices.SortStableFunc(filtered, func(a, b *coredata.CookieCategory) int { +// sortConsentCategories sorts categories in snapshot order: NECESSARY first, +// then NORMAL sorted by ID. The caller is expected to have already excluded +// UNCATEGORISED at load time. +func sortConsentCategories(categories coredata.CookieCategories) { + slices.SortStableFunc(categories, func(a, b *coredata.CookieCategory) int { if d := snapshotCategoryKindOrder(a.Kind) - snapshotCategoryKindOrder(b.Kind); d != 0 { return d } return bytes.Compare(a.ID[:], b.ID[:]) }) - return filtered } func buildSnapshot( @@ -80,7 +74,7 @@ func buildSnapshot( categories coredata.CookieCategories, allPatterns coredata.CookiePatterns, ) coredata.CookieBannerVersionSnapshot { - categories = consentCategories(categories) + sortConsentCategories(categories) cookiesByCategory := make(map[gid.GID]coredata.CookieItems) for _, p := range allPatterns { diff --git a/pkg/coredata/cookie_category.go b/pkg/coredata/cookie_category.go index 8023b3c13..1f6cb063c 100644 --- a/pkg/coredata/cookie_category.go +++ b/pkg/coredata/cookie_category.go @@ -323,6 +323,61 @@ ORDER BY return nil } +// LoadConsentCategoriesByCookieBannerID loads all categories except +// UNCATEGORISED, which is an admin-side inbox never shown to visitors. +func (c *CookieCategories) LoadConsentCategoriesByCookieBannerID( + ctx context.Context, + conn pg.Querier, + scope Scoper, + cookieBannerID gid.GID, +) error { + q := ` +SELECT + id, + organization_id, + cookie_banner_id, + name, + slug, + description, + kind, + rank, + gcm_consent_types, + posthog_consent, + created_at, + updated_at +FROM + cookie_categories +WHERE + %s + AND cookie_banner_id = @cookie_banner_id + AND kind != @excluded_kind +ORDER BY + rank ASC, id ASC; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "cookie_banner_id": cookieBannerID, + "excluded_kind": CookieCategoryKindUncategorised, + } + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query consent cookie categories: %w", err) + } + + categories, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[CookieCategory]) + if err != nil { + return fmt.Errorf("cannot collect consent cookie categories: %w", err) + } + + *c = categories + + return nil +} + func (c *CookieCategory) Insert( ctx context.Context, tx pg.Tx,