Add excluded flag to cookie pattern model

Adds an `excluded` boolean column to the cookie_patterns table
so operators can mark patterns to be omitted from the consent
banner without deleting them. Includes the migration, struct
field, updated SQL queries, and filter support.

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-01 16:19:17 +04:00
parent 8e5c586c95
commit 2192c854a0
4 changed files with 49 additions and 2 deletions

View File

@@ -304,7 +304,7 @@ func (h *patternAnalysisHandler) adoptUncategorisedPatterns(
tx, tx,
scope, scope,
banner.ID, banner.ID,
coredata.NewCookiePatternFilter(&prefixMatchType, nil), coredata.NewCookiePatternFilter(&prefixMatchType, nil, nil),
); err != nil { ); err != nil {
return false, fmt.Errorf("cannot load prefix patterns: %w", err) return false, fmt.Errorf("cannot load prefix patterns: %w", err)
} }
@@ -324,7 +324,7 @@ func (h *patternAnalysisHandler) adoptUncategorisedPatterns(
tx, tx,
scope, scope,
banner.ID, banner.ID,
coredata.NewCookiePatternFilter(&exactMatchType, &uncategorised.ID), coredata.NewCookiePatternFilter(&exactMatchType, &uncategorised.ID, nil),
); err != nil { ); err != nil {
return false, fmt.Errorf("cannot load uncategorised exact patterns: %w", err) return false, fmt.Errorf("cannot load uncategorised exact patterns: %w", err)
} }

View File

@@ -40,6 +40,7 @@ type (
MaxAgeSeconds *int `db:"max_age_seconds"` MaxAgeSeconds *int `db:"max_age_seconds"`
Description string `db:"description"` Description string `db:"description"`
Source CookieSource `db:"source"` Source CookieSource `db:"source"`
Excluded bool `db:"excluded"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"` UpdatedAt time.Time `db:"updated_at"`
} }
@@ -89,6 +90,7 @@ SELECT
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -141,6 +143,7 @@ SELECT
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -197,6 +200,7 @@ SELECT
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -264,6 +268,7 @@ SELECT
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -345,6 +350,7 @@ SELECT
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -396,6 +402,7 @@ INSERT INTO cookie_patterns (
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
) VALUES ( ) VALUES (
@@ -410,6 +417,7 @@ INSERT INTO cookie_patterns (
@max_age_seconds, @max_age_seconds,
@description, @description,
@source, @source,
@excluded,
@created_at, @created_at,
@updated_at @updated_at
) )
@@ -427,6 +435,7 @@ INSERT INTO cookie_patterns (
"max_age_seconds": cp.MaxAgeSeconds, "max_age_seconds": cp.MaxAgeSeconds,
"description": cp.Description, "description": cp.Description,
"source": cp.Source, "source": cp.Source,
"excluded": cp.Excluded,
"created_at": cp.CreatedAt, "created_at": cp.CreatedAt,
"updated_at": cp.UpdatedAt, "updated_at": cp.UpdatedAt,
} }
@@ -462,6 +471,7 @@ INSERT INTO cookie_patterns (
max_age_seconds, max_age_seconds,
description, description,
source, source,
excluded,
created_at, created_at,
updated_at updated_at
) VALUES ( ) VALUES (
@@ -476,6 +486,7 @@ INSERT INTO cookie_patterns (
@max_age_seconds, @max_age_seconds,
@description, @description,
@source, @source,
@excluded,
@created_at, @created_at,
@updated_at @updated_at
) )
@@ -494,6 +505,7 @@ ON CONFLICT (cookie_banner_id, pattern) DO NOTHING
"max_age_seconds": cp.MaxAgeSeconds, "max_age_seconds": cp.MaxAgeSeconds,
"description": cp.Description, "description": cp.Description,
"source": cp.Source, "source": cp.Source,
"excluded": cp.Excluded,
"created_at": cp.CreatedAt, "created_at": cp.CreatedAt,
"updated_at": cp.UpdatedAt, "updated_at": cp.UpdatedAt,
} }
@@ -518,6 +530,7 @@ SET
display_name = @display_name, display_name = @display_name,
max_age_seconds = @max_age_seconds, max_age_seconds = @max_age_seconds,
description = @description, description = @description,
excluded = @excluded,
updated_at = @updated_at updated_at = @updated_at
WHERE WHERE
%s %s
@@ -532,6 +545,7 @@ WHERE
"display_name": cp.DisplayName, "display_name": cp.DisplayName,
"max_age_seconds": cp.MaxAgeSeconds, "max_age_seconds": cp.MaxAgeSeconds,
"description": cp.Description, "description": cp.Description,
"excluded": cp.Excluded,
"updated_at": cp.UpdatedAt, "updated_at": cp.UpdatedAt,
} }
maps.Copy(args, scope.SQLArguments()) maps.Copy(args, scope.SQLArguments())

View File

@@ -22,15 +22,18 @@ import (
type CookiePatternFilter struct { type CookiePatternFilter struct {
matchType *CookiePatternMatchType matchType *CookiePatternMatchType
cookieCategoryID *gid.GID cookieCategoryID *gid.GID
excluded *bool
} }
func NewCookiePatternFilter( func NewCookiePatternFilter(
matchType *CookiePatternMatchType, matchType *CookiePatternMatchType,
cookieCategoryID *gid.GID, cookieCategoryID *gid.GID,
excluded *bool,
) *CookiePatternFilter { ) *CookiePatternFilter {
return &CookiePatternFilter{ return &CookiePatternFilter{
matchType: matchType, matchType: matchType,
cookieCategoryID: cookieCategoryID, cookieCategoryID: cookieCategoryID,
excluded: excluded,
} }
} }
@@ -54,6 +57,13 @@ func (f *CookiePatternFilter) SQLFragment() string {
cookie_category_id = @filter_cookie_category_id::text cookie_category_id = @filter_cookie_category_id::text
ELSE TRUE ELSE TRUE
END END
AND
CASE
WHEN @has_excluded_filter::boolean = false THEN TRUE
WHEN @has_excluded_filter::boolean = true THEN
excluded = @filter_excluded
ELSE TRUE
END
)` )`
} }
@@ -67,6 +77,8 @@ func (f *CookiePatternFilter) SQLArguments() pgx.StrictNamedArgs {
"filter_match_type": nil, "filter_match_type": nil,
"has_cookie_category_id_filter": false, "has_cookie_category_id_filter": false,
"filter_cookie_category_id": nil, "filter_cookie_category_id": nil,
"has_excluded_filter": false,
"filter_excluded": nil,
} }
if f.matchType != nil { if f.matchType != nil {
@@ -79,5 +91,10 @@ func (f *CookiePatternFilter) SQLArguments() pgx.StrictNamedArgs {
args["filter_cookie_category_id"] = *f.cookieCategoryID args["filter_cookie_category_id"] = *f.cookieCategoryID
} }
if f.excluded != nil {
args["has_excluded_filter"] = true
args["filter_excluded"] = *f.excluded
}
return args return args
} }

View File

@@ -0,0 +1,16 @@
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
--
-- 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.
ALTER TABLE cookie_patterns ADD COLUMN excluded BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE cookie_patterns ALTER COLUMN excluded DROP DEFAULT;