Handle cookie banner origin validation + unicity

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-04-13 16:31:08 +04:00
parent 0ce1d8039a
commit d05c3591d3
6 changed files with 124 additions and 6 deletions

View File

@@ -22,6 +22,7 @@ import (
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/page"
@@ -118,10 +119,10 @@ LIMIT 1;
return nil
}
func (b *CookieBanner) LoadActiveByID(
func (b *CookieBanner) LoadActiveByOrigin(
ctx context.Context,
conn pg.Querier,
bannerID gid.GID,
origin string,
) error {
q := `
SELECT
@@ -138,12 +139,12 @@ SELECT
FROM
cookie_banners
WHERE
id = @banner_id
origin = @origin
AND state = 'ACTIVE'
LIMIT 1;
`
args := pgx.StrictNamedArgs{"banner_id": bannerID}
args := pgx.StrictNamedArgs{"origin": origin}
rows, err := conn.Query(ctx, q, args)
if err != nil {
@@ -298,6 +299,12 @@ INSERT INTO cookie_banners (
_, err := tx.Exec(ctx, q, args)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
if pgErr.Code == "23505" && pgErr.ConstraintName == "idx_cookie_banners_unique_active_origin" {
return ErrResourceAlreadyExists
}
}
return fmt.Errorf("cannot insert cookie banner: %w", err)
}
@@ -340,6 +347,12 @@ WHERE
result, err := tx.Exec(ctx, q, args)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
if pgErr.Code == "23505" && pgErr.ConstraintName == "idx_cookie_banners_unique_active_origin" {
return ErrResourceAlreadyExists
}
}
return fmt.Errorf("cannot update cookie banner: %w", err)
}

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.
CREATE UNIQUE INDEX idx_cookie_banners_unique_active_origin
ON cookie_banners (tenant_id, origin) WHERE state = 'ACTIVE';