Derive consent mode from geolocation, not banner config

The consent mode is now determined dynamically by the visitor's
country and its applicable regulation. The configured consent_mode
column is dropped from cookie_banners and added to
cookie_consent_records to persist the geo-derived mode at
consent-recording time. When no regulation matches, the default
is OPT_OUT.

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-13 12:17:34 +04:00
parent e9d786c5d6
commit e739473bcd
30 changed files with 68 additions and 246 deletions

View File

@@ -21,10 +21,7 @@ import {
Card, Card,
Field, Field,
Input, Input,
Label,
Option,
PageHeader, PageHeader,
Select,
useToast, useToast,
} from "@probo/ui"; } from "@probo/ui";
import { type FormEvent, useState } from "react"; import { type FormEvent, useState } from "react";
@@ -63,7 +60,6 @@ export default function NewCookieBannerPage() {
const [cookiePolicyUrl, setCookiePolicyUrl] = useState(""); const [cookiePolicyUrl, setCookiePolicyUrl] = useState("");
const [privacyPolicyUrl, setPrivacyPolicyUrl] = useState(""); const [privacyPolicyUrl, setPrivacyPolicyUrl] = useState("");
const [consentExpiryDays, setConsentExpiryDays] = useState("365"); const [consentExpiryDays, setConsentExpiryDays] = useState("365");
const [consentMode, setConsentMode] = useState("OPT_IN");
const handleSubmit = (e: FormEvent<HTMLFormElement>) => { const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
@@ -77,7 +73,6 @@ export default function NewCookieBannerPage() {
cookiePolicyUrl, cookiePolicyUrl,
privacyPolicyUrl: privacyPolicyUrl || undefined, privacyPolicyUrl: privacyPolicyUrl || undefined,
consentExpiryDays: parseInt(consentExpiryDays, 10), consentExpiryDays: parseInt(consentExpiryDays, 10),
consentMode: consentMode as "OPT_IN" | "OPT_OUT",
}, },
}, },
onCompleted(data) { onCompleted(data) {
@@ -155,9 +150,7 @@ export default function NewCookieBannerPage() {
/> />
</Field> </Field>
<div className="grid grid-cols-2 gap-4"> <Field label={__("Consent Expiry (days)")}>
<div className="space-y-2">
<Label>{__("Consent Expiry (days)")}</Label>
<Input <Input
type="number" type="number"
value={consentExpiryDays} value={consentExpiryDays}
@@ -165,16 +158,7 @@ export default function NewCookieBannerPage() {
min="1" min="1"
required required
/> />
</div> </Field>
<div className="space-y-2">
<Label>{__("Consent Mode")}</Label>
<Select value={consentMode} onValueChange={setConsentMode}>
<Option value="OPT_IN">{__("Opt-in")}</Option>
<Option value="OPT_OUT">{__("Opt-out")}</Option>
</Select>
</div>
</div>
<Button type="submit" disabled={isCreating}> <Button type="submit" disabled={isCreating}>
{isCreating ? __("Creating...") : __("Create Banner")} {isCreating ? __("Creating...") : __("Create Banner")}

View File

@@ -30,7 +30,6 @@ const bannerSettingsFormFragment = graphql`
cookiePolicyUrl cookiePolicyUrl
privacyPolicyUrl privacyPolicyUrl
consentExpiryDays consentExpiryDays
consentMode
defaultLanguage defaultLanguage
} }
`; `;
@@ -44,7 +43,6 @@ const updateBannerMutation = graphql`
cookiePolicyUrl cookiePolicyUrl
privacyPolicyUrl privacyPolicyUrl
consentExpiryDays consentExpiryDays
consentMode
defaultLanguage defaultLanguage
latestVersion { latestVersion {
id id
@@ -61,7 +59,6 @@ interface BannerSettingsFormValues {
cookiePolicyUrl: string; cookiePolicyUrl: string;
privacyPolicyUrl: string; privacyPolicyUrl: string;
consentExpiryDays: string; consentExpiryDays: string;
consentMode: "OPT_IN" | "OPT_OUT";
defaultLanguage: string; defaultLanguage: string;
} }
@@ -83,7 +80,6 @@ export function BannerSettingsForm({ cookieBannerKey }: BannerSettingsFormProps)
cookiePolicyUrl: banner.cookiePolicyUrl, cookiePolicyUrl: banner.cookiePolicyUrl,
privacyPolicyUrl: banner.privacyPolicyUrl ?? "", privacyPolicyUrl: banner.privacyPolicyUrl ?? "",
consentExpiryDays: String(banner.consentExpiryDays), consentExpiryDays: String(banner.consentExpiryDays),
consentMode: banner.consentMode,
defaultLanguage: banner.defaultLanguage, defaultLanguage: banner.defaultLanguage,
}, },
}); });
@@ -97,7 +93,6 @@ export function BannerSettingsForm({ cookieBannerKey }: BannerSettingsFormProps)
cookiePolicyUrl: data.cookiePolicyUrl, cookiePolicyUrl: data.cookiePolicyUrl,
privacyPolicyUrl: data.privacyPolicyUrl || undefined, privacyPolicyUrl: data.privacyPolicyUrl || undefined,
consentExpiryDays: parseInt(data.consentExpiryDays, 10), consentExpiryDays: parseInt(data.consentExpiryDays, 10),
consentMode: data.consentMode,
defaultLanguage: data.defaultLanguage, defaultLanguage: data.defaultLanguage,
}, },
}, },
@@ -131,7 +126,7 @@ export function BannerSettingsForm({ cookieBannerKey }: BannerSettingsFormProps)
<Input {...register("privacyPolicyUrl")} /> <Input {...register("privacyPolicyUrl")} />
</Field> </Field>
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>{__("Consent Expiry (days)")}</Label> <Label>{__("Consent Expiry (days)")}</Label>
<Input <Input
@@ -141,19 +136,6 @@ export function BannerSettingsForm({ cookieBannerKey }: BannerSettingsFormProps)
required required
/> />
</div> </div>
<div className="space-y-2">
<Label>{__("Consent Mode")}</Label>
<Controller
name="consentMode"
control={control}
render={({ field }) => (
<Select value={field.value} onValueChange={field.onChange}>
<Option value="OPT_IN">{__("Opt-in")}</Option>
<Option value="OPT_OUT">{__("Opt-out")}</Option>
</Select>
)}
/>
</div>
<div className="space-y-2"> <div className="space-y-2">
<Label>{__("Default Language")}</Label> <Label>{__("Default Language")}</Label>
<Controller <Controller

View File

@@ -41,7 +41,6 @@ func TestCookieBanner_Create(t *testing.T) {
state state
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt
@@ -65,7 +64,6 @@ func TestCookieBanner_Create(t *testing.T) {
State string `json:"state"` State string `json:"state"`
CookiePolicyUrl string `json:"cookiePolicyUrl"` CookiePolicyUrl string `json:"cookiePolicyUrl"`
ConsentExpiryDays int `json:"consentExpiryDays"` ConsentExpiryDays int `json:"consentExpiryDays"`
ConsentMode string `json:"consentMode"`
ShowBranding bool `json:"showBranding"` ShowBranding bool `json:"showBranding"`
DefaultLanguage string `json:"defaultLanguage"` DefaultLanguage string `json:"defaultLanguage"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
@@ -82,7 +80,6 @@ func TestCookieBanner_Create(t *testing.T) {
"origin": origin, "origin": origin,
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}, },
}, &result) }, &result)
@@ -93,7 +90,6 @@ func TestCookieBanner_Create(t *testing.T) {
assert.Equal(t, "ACTIVE", node.State) assert.Equal(t, "ACTIVE", node.State)
assert.Equal(t, "https://example.com/cookies", node.CookiePolicyUrl) assert.Equal(t, "https://example.com/cookies", node.CookiePolicyUrl)
assert.Equal(t, 365, node.ConsentExpiryDays) assert.Equal(t, 365, node.ConsentExpiryDays)
assert.Equal(t, "OPT_IN", node.ConsentMode)
assert.Equal(t, "en", node.DefaultLanguage) assert.Equal(t, "en", node.DefaultLanguage)
assert.NotEmpty(t, node.CreatedAt) assert.NotEmpty(t, node.CreatedAt)
assert.NotEmpty(t, node.UpdatedAt) assert.NotEmpty(t, node.UpdatedAt)
@@ -110,7 +106,6 @@ func TestCookieBanner_Create(t *testing.T) {
node { node {
id id
privacyPolicyUrl privacyPolicyUrl
consentMode
} }
} }
} }
@@ -123,7 +118,6 @@ func TestCookieBanner_Create(t *testing.T) {
Node struct { Node struct {
ID string `json:"id"` ID string `json:"id"`
PrivacyPolicyUrl *string `json:"privacyPolicyUrl"` PrivacyPolicyUrl *string `json:"privacyPolicyUrl"`
ConsentMode string `json:"consentMode"`
} `json:"node"` } `json:"node"`
} `json:"cookieBannerEdge"` } `json:"cookieBannerEdge"`
} `json:"createCookieBanner"` } `json:"createCookieBanner"`
@@ -137,7 +131,6 @@ func TestCookieBanner_Create(t *testing.T) {
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"privacyPolicyUrl": "https://example.com/privacy", "privacyPolicyUrl": "https://example.com/privacy",
"consentExpiryDays": 180, "consentExpiryDays": 180,
"consentMode": "OPT_OUT",
}, },
}, &result) }, &result)
@@ -146,7 +139,6 @@ func TestCookieBanner_Create(t *testing.T) {
assert.NotEmpty(t, node.ID) assert.NotEmpty(t, node.ID)
require.NotNil(t, node.PrivacyPolicyUrl) require.NotNil(t, node.PrivacyPolicyUrl)
assert.Equal(t, "https://example.com/privacy", *node.PrivacyPolicyUrl) assert.Equal(t, "https://example.com/privacy", *node.PrivacyPolicyUrl)
assert.Equal(t, "OPT_OUT", node.ConsentMode)
}) })
t.Run("creates default categories", func(t *testing.T) { t.Run("creates default categories", func(t *testing.T) {
@@ -220,7 +212,6 @@ func TestCookieBanner_Create(t *testing.T) {
"origin": origin, "origin": origin,
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}, },
}) })
require.Error(t, err) require.Error(t, err)
@@ -243,7 +234,6 @@ func TestCookieBanner_Create(t *testing.T) {
"origin": factory.SafeOrigin(), "origin": factory.SafeOrigin(),
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}, },
}) })
require.Error(t, err) require.Error(t, err)
@@ -306,7 +296,6 @@ func TestCookieBanner_Update(t *testing.T) {
updateCookieBanner(input: $input) { updateCookieBanner(input: $input) {
cookieBanner { cookieBanner {
consentExpiryDays consentExpiryDays
consentMode
defaultLanguage defaultLanguage
} }
} }
@@ -317,7 +306,6 @@ func TestCookieBanner_Update(t *testing.T) {
UpdateCookieBanner struct { UpdateCookieBanner struct {
CookieBanner struct { CookieBanner struct {
ConsentExpiryDays int `json:"consentExpiryDays"` ConsentExpiryDays int `json:"consentExpiryDays"`
ConsentMode string `json:"consentMode"`
DefaultLanguage string `json:"defaultLanguage"` DefaultLanguage string `json:"defaultLanguage"`
} `json:"cookieBanner"` } `json:"cookieBanner"`
} `json:"updateCookieBanner"` } `json:"updateCookieBanner"`
@@ -327,14 +315,12 @@ func TestCookieBanner_Update(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"cookieBannerId": bannerID, "cookieBannerId": bannerID,
"consentExpiryDays": 90, "consentExpiryDays": 90,
"consentMode": "OPT_OUT",
"defaultLanguage": "fr", "defaultLanguage": "fr",
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 90, result.UpdateCookieBanner.CookieBanner.ConsentExpiryDays) assert.Equal(t, 90, result.UpdateCookieBanner.CookieBanner.ConsentExpiryDays)
assert.Equal(t, "OPT_OUT", result.UpdateCookieBanner.CookieBanner.ConsentMode)
assert.Equal(t, "fr", result.UpdateCookieBanner.CookieBanner.DefaultLanguage) assert.Equal(t, "fr", result.UpdateCookieBanner.CookieBanner.DefaultLanguage)
}) })
} }
@@ -574,7 +560,6 @@ func TestCookieBanner_Node(t *testing.T) {
name name
origin origin
state state
consentMode
} }
} }
} }
@@ -586,7 +571,6 @@ func TestCookieBanner_Node(t *testing.T) {
Name string `json:"name"` Name string `json:"name"`
Origin string `json:"origin"` Origin string `json:"origin"`
State string `json:"state"` State string `json:"state"`
ConsentMode string `json:"consentMode"`
} `json:"node"` } `json:"node"`
} }
@@ -842,7 +826,6 @@ func TestCookieBanner_RBAC(t *testing.T) {
"origin": factory.SafeOrigin(), "origin": factory.SafeOrigin(),
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}, },
}) })
testutil.RequireForbiddenError(t, err, "viewer should not be able to create cookie banner") testutil.RequireForbiddenError(t, err, "viewer should not be able to create cookie banner")

View File

@@ -153,7 +153,6 @@ func TestCookieBannerVersioning_NoOpUpdates(t *testing.T) {
bannerID := factory.CreateCookieBanner(owner, factory.Attrs{ bannerID := factory.CreateCookieBanner(owner, factory.Attrs{
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}) })
published := publishBanner(t, owner, bannerID) published := publishBanner(t, owner, bannerID)
@@ -172,7 +171,6 @@ func TestCookieBannerVersioning_NoOpUpdates(t *testing.T) {
"cookieBannerId": bannerID, "cookieBannerId": bannerID,
"cookiePolicyUrl": "https://example.com/cookies", "cookiePolicyUrl": "https://example.com/cookies",
"consentExpiryDays": 365, "consentExpiryDays": 365,
"consentMode": "OPT_IN",
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -1239,7 +1239,6 @@ func CreateCookieBanner(c *testutil.Client, attrs ...Attrs) string {
"origin": a.getString("origin", SafeOrigin()), "origin": a.getString("origin", SafeOrigin()),
"cookiePolicyUrl": a.getString("cookiePolicyUrl", "https://example.com/cookies"), "cookiePolicyUrl": a.getString("cookiePolicyUrl", "https://example.com/cookies"),
"consentExpiryDays": a.getInt("consentExpiryDays", 365), "consentExpiryDays": a.getInt("consentExpiryDays", 365),
"consentMode": a.getString("consentMode", "OPT_IN"),
} }
if ppURL := a.getStringPtr("privacyPolicyUrl"); ppURL != nil { if ppURL := a.getStringPtr("privacyPolicyUrl"); ppURL != nil {
input["privacyPolicyUrl"] = *ppURL input["privacyPolicyUrl"] = *ppURL
@@ -1295,11 +1294,6 @@ func (b *CookieBannerBuilder) WithConsentExpiryDays(days int) *CookieBannerBuild
return b return b
} }
func (b *CookieBannerBuilder) WithConsentMode(mode string) *CookieBannerBuilder {
b.attrs["consentMode"] = mode
return b
}
func (b *CookieBannerBuilder) Create() string { func (b *CookieBannerBuilder) Create() string {
return CreateCookieBanner(b.client, b.attrs) return CreateCookieBanner(b.client, b.attrs)
} }

View File

@@ -49,7 +49,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt

View File

@@ -89,30 +89,6 @@ export const description: INodeProperties[] = [
description: 'Number of days before consent expires', description: 'Number of days before consent expires',
required: true, required: true,
}, },
{
displayName: 'Consent Mode',
name: 'consentMode',
type: 'options',
displayOptions: {
show: {
resource: ['cookieBanner'],
operation: ['create'],
},
},
options: [
{
name: 'Opt In',
value: 'OPT_IN',
},
{
name: 'Opt Out',
value: 'OPT_OUT',
},
],
default: 'OPT_IN',
description: 'The consent mode for the cookie banner',
required: true,
},
{ {
displayName: 'Privacy Policy URL', displayName: 'Privacy Policy URL',
name: 'privacyPolicyUrl', name: 'privacyPolicyUrl',
@@ -137,7 +113,6 @@ export async function execute(
const origin = this.getNodeParameter('origin', itemIndex) as string; const origin = this.getNodeParameter('origin', itemIndex) as string;
const cookiePolicyUrl = this.getNodeParameter('cookiePolicyUrl', itemIndex) as string; const cookiePolicyUrl = this.getNodeParameter('cookiePolicyUrl', itemIndex) as string;
const consentExpiryDays = this.getNodeParameter('consentExpiryDays', itemIndex) as number; const consentExpiryDays = this.getNodeParameter('consentExpiryDays', itemIndex) as number;
const consentMode = this.getNodeParameter('consentMode', itemIndex) as string;
const privacyPolicyUrl = this.getNodeParameter('privacyPolicyUrl', itemIndex, '') as string; const privacyPolicyUrl = this.getNodeParameter('privacyPolicyUrl', itemIndex, '') as string;
const query = ` const query = `
@@ -152,7 +127,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt
@@ -169,7 +143,6 @@ export async function execute(
origin, origin,
cookiePolicyUrl, cookiePolicyUrl,
consentExpiryDays, consentExpiryDays,
consentMode,
}; };
if (privacyPolicyUrl) input.privacyPolicyUrl = privacyPolicyUrl; if (privacyPolicyUrl) input.privacyPolicyUrl = privacyPolicyUrl;

View File

@@ -49,7 +49,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt

View File

@@ -49,7 +49,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt

View File

@@ -84,7 +84,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt

View File

@@ -69,33 +69,6 @@ export const description: INodeProperties[] = [
default: 0, default: 0,
description: 'Number of days before consent expires (0 to leave unchanged)', description: 'Number of days before consent expires (0 to leave unchanged)',
}, },
{
displayName: 'Consent Mode',
name: 'consentMode',
type: 'options',
displayOptions: {
show: {
resource: ['cookieBanner'],
operation: ['update'],
},
},
options: [
{
name: '(Unchanged)',
value: '',
},
{
name: 'Opt In',
value: 'OPT_IN',
},
{
name: 'Opt Out',
value: 'OPT_OUT',
},
],
default: '',
description: 'The consent mode for the cookie banner',
},
{ {
displayName: 'Default Language', displayName: 'Default Language',
name: 'defaultLanguage', name: 'defaultLanguage',
@@ -141,7 +114,6 @@ export async function execute(
const name = this.getNodeParameter('name', itemIndex, '') as string; const name = this.getNodeParameter('name', itemIndex, '') as string;
const cookiePolicyUrl = this.getNodeParameter('cookiePolicyUrl', itemIndex, '') as string; const cookiePolicyUrl = this.getNodeParameter('cookiePolicyUrl', itemIndex, '') as string;
const consentExpiryDays = this.getNodeParameter('consentExpiryDays', itemIndex, 0) as number; const consentExpiryDays = this.getNodeParameter('consentExpiryDays', itemIndex, 0) as number;
const consentMode = this.getNodeParameter('consentMode', itemIndex, '') as string;
const defaultLanguage = this.getNodeParameter('defaultLanguage', itemIndex, '') as string; const defaultLanguage = this.getNodeParameter('defaultLanguage', itemIndex, '') as string;
const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as { const additionalFields = this.getNodeParameter('additionalFields', itemIndex, {}) as {
privacyPolicyUrl?: string; privacyPolicyUrl?: string;
@@ -158,7 +130,6 @@ export async function execute(
privacyPolicyUrl privacyPolicyUrl
cookiePolicyUrl cookiePolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt
@@ -172,7 +143,6 @@ export async function execute(
if (name) input.name = name; if (name) input.name = name;
if (cookiePolicyUrl) input.cookiePolicyUrl = cookiePolicyUrl; if (cookiePolicyUrl) input.cookiePolicyUrl = cookiePolicyUrl;
if (consentExpiryDays) input.consentExpiryDays = consentExpiryDays; if (consentExpiryDays) input.consentExpiryDays = consentExpiryDays;
if (consentMode) input.consentMode = consentMode;
if (defaultLanguage) input.defaultLanguage = defaultLanguage; if (defaultLanguage) input.defaultLanguage = defaultLanguage;
if (additionalFields.privacyPolicyUrl !== undefined) { if (additionalFields.privacyPolicyUrl !== undefined) {
input.privacyPolicyUrl = additionalFields.privacyPolicyUrl === '' ? null : additionalFields.privacyPolicyUrl; input.privacyPolicyUrl = additionalFields.privacyPolicyUrl === '' ? null : additionalFields.privacyPolicyUrl;

View File

@@ -58,7 +58,6 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
flagCookiePolicyUrl string flagCookiePolicyUrl string
flagPrivacyPolicyUrl string flagPrivacyPolicyUrl string
flagConsentExpiry int flagConsentExpiry int
flagConsentMode string
) )
cmd := &cobra.Command{ cmd := &cobra.Command{
@@ -106,17 +105,6 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
return err return err
} }
} }
if flagConsentMode == "" {
if err := huh.NewSelect[string]().
Title("Consent mode").
Options(
huh.NewOption("Opt-In", "OPT_IN"),
huh.NewOption("Opt-Out", "OPT_OUT"),
).
Value(&flagConsentMode).Run(); err != nil {
return err
}
}
} }
if flagName == "" { if flagName == "" {
@@ -128,9 +116,6 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
if flagCookiePolicyUrl == "" { if flagCookiePolicyUrl == "" {
return fmt.Errorf("cookie-policy-url is required; pass --cookie-policy-url or run interactively") return fmt.Errorf("cookie-policy-url is required; pass --cookie-policy-url or run interactively")
} }
if flagConsentMode == "" {
return fmt.Errorf("consent-mode is required; pass --consent-mode or run interactively")
}
input := map[string]any{ input := map[string]any{
"organizationId": flagOrg, "organizationId": flagOrg,
@@ -138,7 +123,6 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
"origin": flagOrigin, "origin": flagOrigin,
"cookiePolicyUrl": flagCookiePolicyUrl, "cookiePolicyUrl": flagCookiePolicyUrl,
"consentExpiryDays": flagConsentExpiry, "consentExpiryDays": flagConsentExpiry,
"consentMode": flagConsentMode,
} }
if flagPrivacyPolicyUrl != "" { if flagPrivacyPolicyUrl != "" {
input["privacyPolicyUrl"] = flagPrivacyPolicyUrl input["privacyPolicyUrl"] = flagPrivacyPolicyUrl
@@ -167,7 +151,6 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
cmd.Flags().StringVar(&flagCookiePolicyUrl, "cookie-policy-url", "", "Cookie policy URL (required)") cmd.Flags().StringVar(&flagCookiePolicyUrl, "cookie-policy-url", "", "Cookie policy URL (required)")
cmd.Flags().StringVar(&flagPrivacyPolicyUrl, "privacy-policy-url", "", "Privacy policy URL") cmd.Flags().StringVar(&flagPrivacyPolicyUrl, "privacy-policy-url", "", "Privacy policy URL")
cmd.Flags().IntVar(&flagConsentExpiry, "consent-expiry-days", 365, "Days until consent expires") cmd.Flags().IntVar(&flagConsentExpiry, "consent-expiry-days", 365, "Days until consent expires")
cmd.Flags().StringVar(&flagConsentMode, "consent-mode", "", "Consent mode: OPT_IN or OPT_OUT (required)")
return cmd return cmd
} }

View File

@@ -36,7 +36,6 @@ query($id: ID!, $first: Int, $after: CursorKey) {
name name
origin origin
state state
consentMode
} }
} }
pageInfo { pageInfo {
@@ -54,7 +53,6 @@ type banner struct {
Name string `json:"name"` Name string `json:"name"`
Origin string `json:"origin"` Origin string `json:"origin"`
State string `json:"state"` State string `json:"state"`
ConsentMode string `json:"consentMode"`
} }
func NewCmdList(f *cmdutil.Factory) *cobra.Command { func NewCmdList(f *cmdutil.Factory) *cobra.Command {
@@ -140,10 +138,10 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
rows := make([][]string, 0, len(banners)) rows := make([][]string, 0, len(banners))
for _, b := range banners { for _, b := range banners {
rows = append(rows, []string{b.ID, b.Name, b.Origin, b.State, b.ConsentMode}) rows = append(rows, []string{b.ID, b.Name, b.Origin, b.State})
} }
t := cmdutil.NewTable("ID", "NAME", "ORIGIN", "STATE", "CONSENT MODE").Rows(rows...) t := cmdutil.NewTable("ID", "NAME", "ORIGIN", "STATE").Rows(rows...)
_, _ = fmt.Fprintln(f.IOStreams.Out, t) _, _ = fmt.Fprintln(f.IOStreams.Out, t)
if totalCount > len(banners) { if totalCount > len(banners) {

View File

@@ -49,7 +49,6 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
flagCookiePolicyUrl string flagCookiePolicyUrl string
flagPrivacyPolicyUrl string flagPrivacyPolicyUrl string
flagConsentExpiry int flagConsentExpiry int
flagConsentMode string
flagDefaultLanguage string flagDefaultLanguage string
) )
@@ -90,9 +89,6 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
if cmd.Flags().Changed("consent-expiry-days") { if cmd.Flags().Changed("consent-expiry-days") {
input["consentExpiryDays"] = flagConsentExpiry input["consentExpiryDays"] = flagConsentExpiry
} }
if cmd.Flags().Changed("consent-mode") {
input["consentMode"] = flagConsentMode
}
if cmd.Flags().Changed("default-language") { if cmd.Flags().Changed("default-language") {
input["defaultLanguage"] = flagDefaultLanguage input["defaultLanguage"] = flagDefaultLanguage
} }
@@ -122,7 +118,6 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
cmd.Flags().StringVar(&flagCookiePolicyUrl, "cookie-policy-url", "", "Cookie policy URL") cmd.Flags().StringVar(&flagCookiePolicyUrl, "cookie-policy-url", "", "Cookie policy URL")
cmd.Flags().StringVar(&flagPrivacyPolicyUrl, "privacy-policy-url", "", "Privacy policy URL") cmd.Flags().StringVar(&flagPrivacyPolicyUrl, "privacy-policy-url", "", "Privacy policy URL")
cmd.Flags().IntVar(&flagConsentExpiry, "consent-expiry-days", 0, "Days until consent expires") cmd.Flags().IntVar(&flagConsentExpiry, "consent-expiry-days", 0, "Days until consent expires")
cmd.Flags().StringVar(&flagConsentMode, "consent-mode", "", "Consent mode: OPT_IN or OPT_OUT")
cmd.Flags().StringVar(&flagDefaultLanguage, "default-language", "", "Default language code") cmd.Flags().StringVar(&flagDefaultLanguage, "default-language", "", "Default language code")
return cmd return cmd

View File

@@ -36,7 +36,6 @@ query($id: ID!) {
cookiePolicyUrl cookiePolicyUrl
privacyPolicyUrl privacyPolicyUrl
consentExpiryDays consentExpiryDays
consentMode
showBranding showBranding
defaultLanguage defaultLanguage
createdAt createdAt
@@ -56,7 +55,6 @@ type viewResponse struct {
CookiePolicyUrl string `json:"cookiePolicyUrl"` CookiePolicyUrl string `json:"cookiePolicyUrl"`
PrivacyPolicyUrl *string `json:"privacyPolicyUrl"` PrivacyPolicyUrl *string `json:"privacyPolicyUrl"`
ConsentExpiryDays int `json:"consentExpiryDays"` ConsentExpiryDays int `json:"consentExpiryDays"`
ConsentMode string `json:"consentMode"`
ShowBranding bool `json:"showBranding"` ShowBranding bool `json:"showBranding"`
DefaultLanguage string `json:"defaultLanguage"` DefaultLanguage string `json:"defaultLanguage"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
@@ -122,7 +120,6 @@ func NewCmdView(f *cmdutil.Factory) *cobra.Command {
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("ID:"), v.ID) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("ID:"), v.ID)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Origin:"), v.Origin) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Origin:"), v.Origin)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("State:"), v.State) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("State:"), v.State)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Consent Mode:"), v.ConsentMode)
_, _ = fmt.Fprintf(out, "%s%d days\n", label.Render("Consent Expiry:"), v.ConsentExpiryDays) _, _ = fmt.Fprintf(out, "%s%d days\n", label.Render("Consent Expiry:"), v.ConsentExpiryDays)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Default Language:"), v.DefaultLanguage) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Default Language:"), v.DefaultLanguage)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Cookie Policy:"), v.CookiePolicyUrl) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Cookie Policy:"), v.CookiePolicyUrl)

View File

@@ -134,8 +134,8 @@ func RegulationForCountry(cc coredata.CountryCode) Regulation {
// the visitor gives explicit consent; OPT_OUT means cookies may fire // the visitor gives explicit consent; OPT_OUT means cookies may fire
// immediately but the visitor must be offered a way to opt out. // immediately but the visitor must be offered a way to opt out.
// //
// When the regulation is unknown or RegulationNone, it returns an empty // When the regulation is unknown or RegulationNone, it defaults to
// string so the caller can fall back to the banner's configured default. // OPT_OUT (cookies may fire immediately, visitor can opt out).
func ConsentModeForRegulation(r Regulation) string { func ConsentModeForRegulation(r Regulation) string {
switch r { switch r {
case RegulationGDPR, case RegulationGDPR,
@@ -157,6 +157,6 @@ func ConsentModeForRegulation(r Regulation) string {
return ConsentModeOptOut return ConsentModeOptOut
default: default:
return "" return ConsentModeOptOut
} }
} }

View File

@@ -51,7 +51,6 @@ type (
PrivacyPolicyURL *string PrivacyPolicyURL *string
CookiePolicyURL string CookiePolicyURL string
ConsentExpiryDays int ConsentExpiryDays int
ConsentMode coredata.CookieConsentMode
} }
CreateCookieCategoryRequest struct { CreateCookieCategoryRequest struct {
@@ -68,7 +67,6 @@ type (
PrivacyPolicyURL *string PrivacyPolicyURL *string
CookiePolicyURL *string CookiePolicyURL *string
ConsentExpiryDays *int ConsentExpiryDays *int
ConsentMode *coredata.CookieConsentMode
DefaultLanguage *string DefaultLanguage *string
} }
@@ -107,6 +105,7 @@ type (
SdkVersion string SdkVersion string
Regulation *Regulation Regulation *Regulation
CountryCode *coredata.CountryCode CountryCode *coredata.CountryCode
ConsentMode *coredata.CookieConsentMode
} }
DetectedCookie struct { DetectedCookie struct {
@@ -231,7 +230,6 @@ func (r *CreateCookieBannerRequest) Validate() error {
v.Check(r.PrivacyPolicyURL, "privacy_policy_url", validator.URL()) v.Check(r.PrivacyPolicyURL, "privacy_policy_url", validator.URL())
v.Check(r.CookiePolicyURL, "cookie_policy_url", validator.Required(), validator.URL()) v.Check(r.CookiePolicyURL, "cookie_policy_url", validator.Required(), validator.URL())
v.Check(r.ConsentExpiryDays, "consent_expiry_days", validator.Required(), validator.Min(1)) v.Check(r.ConsentExpiryDays, "consent_expiry_days", validator.Required(), validator.Min(1))
v.Check(r.ConsentMode, "consent_mode", validator.Required(), validator.OneOfSlice(coredata.CookieConsentModes()))
return v.Error() return v.Error()
} }
@@ -244,7 +242,6 @@ func (r *UpdateCookieBannerRequest) Validate() error {
v.Check(r.PrivacyPolicyURL, "privacy_policy_url", validator.URL()) v.Check(r.PrivacyPolicyURL, "privacy_policy_url", validator.URL())
v.Check(r.CookiePolicyURL, "cookie_policy_url", validator.URL()) v.Check(r.CookiePolicyURL, "cookie_policy_url", validator.URL())
v.Check(r.ConsentExpiryDays, "consent_expiry_days", validator.Min(1)) v.Check(r.ConsentExpiryDays, "consent_expiry_days", validator.Min(1))
v.Check(r.ConsentMode, "consent_mode", validator.OneOfSlice(coredata.CookieConsentModes()))
v.Check(r.DefaultLanguage, "default_language", validator.OneOfSlice(SupportedLanguages)) v.Check(r.DefaultLanguage, "default_language", validator.OneOfSlice(SupportedLanguages))
return v.Error() return v.Error()
@@ -581,7 +578,6 @@ func (s *Service) CreateCookieBanner(
PrivacyPolicyURL: req.PrivacyPolicyURL, PrivacyPolicyURL: req.PrivacyPolicyURL,
CookiePolicyURL: req.CookiePolicyURL, CookiePolicyURL: req.CookiePolicyURL,
ConsentExpiryDays: req.ConsentExpiryDays, ConsentExpiryDays: req.ConsentExpiryDays,
ConsentMode: req.ConsentMode,
ShowBranding: s.showBranding, ShowBranding: s.showBranding,
DefaultLanguage: "en", DefaultLanguage: "en",
CreatedAt: now, CreatedAt: now,
@@ -857,10 +853,9 @@ func (s *Service) UpdateCookieBanner(
privacyChanged := req.PrivacyPolicyURL != nil && !ptrEqual(req.PrivacyPolicyURL, banner.PrivacyPolicyURL) privacyChanged := req.PrivacyPolicyURL != nil && !ptrEqual(req.PrivacyPolicyURL, banner.PrivacyPolicyURL)
cookiePolicyChanged := req.CookiePolicyURL != nil && *req.CookiePolicyURL != banner.CookiePolicyURL cookiePolicyChanged := req.CookiePolicyURL != nil && *req.CookiePolicyURL != banner.CookiePolicyURL
expiryChanged := req.ConsentExpiryDays != nil && *req.ConsentExpiryDays != banner.ConsentExpiryDays expiryChanged := req.ConsentExpiryDays != nil && *req.ConsentExpiryDays != banner.ConsentExpiryDays
consentModeChanged := req.ConsentMode != nil && *req.ConsentMode != banner.ConsentMode
defaultLangChanged := req.DefaultLanguage != nil && *req.DefaultLanguage != banner.DefaultLanguage defaultLangChanged := req.DefaultLanguage != nil && *req.DefaultLanguage != banner.DefaultLanguage
snapshotChanged := privacyChanged || cookiePolicyChanged || expiryChanged || consentModeChanged || defaultLangChanged snapshotChanged := privacyChanged || cookiePolicyChanged || expiryChanged || defaultLangChanged
if !nameChanged && !snapshotChanged { if !nameChanged && !snapshotChanged {
return nil return nil
@@ -878,9 +873,6 @@ func (s *Service) UpdateCookieBanner(
if req.ConsentExpiryDays != nil { if req.ConsentExpiryDays != nil {
banner.ConsentExpiryDays = *req.ConsentExpiryDays banner.ConsentExpiryDays = *req.ConsentExpiryDays
} }
if req.ConsentMode != nil {
banner.ConsentMode = *req.ConsentMode
}
if req.DefaultLanguage != nil { if req.DefaultLanguage != nil {
banner.DefaultLanguage = *req.DefaultLanguage banner.DefaultLanguage = *req.DefaultLanguage
} }
@@ -1609,11 +1601,9 @@ func (s *Service) GetActiveBannerConfig(
} }
config.Regulation = regulation config.Regulation = regulation
if cm := ConsentModeForRegulation(regulation); cm != "" { config.ConsentMode = ConsentModeForRegulation(regulation)
config.ConsentMode = cm
}
if !isLegacySDK(sdkVersion) { if !isLegacySDK(sdkVersion) {
remapTextsForConsentMode(config.Texts, config.ConsentMode, regulation) remapTextsForConsentMode(config.Texts, config.ConsentMode)
} }
return config, nil return config, nil
@@ -1677,7 +1667,6 @@ func buildBannerConfig(
PrivacyPolicyURL: privacyPolicyURL, PrivacyPolicyURL: privacyPolicyURL,
CookiePolicyURL: snapshot.CookiePolicyURL, CookiePolicyURL: snapshot.CookiePolicyURL,
ConsentExpiryDays: snapshot.ConsentExpiryDays, ConsentExpiryDays: snapshot.ConsentExpiryDays,
ConsentMode: snapshot.ConsentMode,
ShowBranding: banner.ShowBranding, ShowBranding: banner.ShowBranding,
Categories: categories, Categories: categories,
Texts: texts, Texts: texts,
@@ -1687,25 +1676,17 @@ func buildBannerConfig(
// remapTextsForConsentMode overrides the generic banner text keys with // remapTextsForConsentMode overrides the generic banner text keys with
// mode-specific variants so the client renders the appropriate copy // mode-specific variants so the client renders the appropriate copy
// without needing consent-mode awareness itself. // without needing consent-mode awareness itself.
func remapTextsForConsentMode(texts map[string]string, consentMode string, regulation Regulation) { func remapTextsForConsentMode(texts map[string]string, consentMode string) {
if texts == nil { if texts == nil {
return return
} }
switch { if consentMode == ConsentModeOptOut {
case consentMode == ConsentModeOptOut:
remapTextKey(texts, "banner_title_opt_out", "banner_title") remapTextKey(texts, "banner_title_opt_out", "banner_title")
remapTextKey(texts, "banner_description_opt_out", "banner_description") remapTextKey(texts, "banner_description_opt_out", "banner_description")
remapTextKey(texts, "button_acknowledge", "button_accept_all") remapTextKey(texts, "button_acknowledge", "button_accept_all")
remapTextKey(texts, "button_opt_out", "button_reject_all") remapTextKey(texts, "button_opt_out", "button_reject_all")
texts["button_customize"] = "" texts["button_customize"] = ""
case regulation == RegulationNone:
remapTextKey(texts, "banner_title_notice", "banner_title")
remapTextKey(texts, "banner_description_notice", "banner_description")
remapTextKey(texts, "button_dismiss", "button_accept_all")
texts["button_reject_all"] = ""
texts["button_customize"] = ""
} }
} }
@@ -1964,6 +1945,7 @@ func (s *Service) RecordConsent(
SdkVersion: req.SdkVersion, SdkVersion: req.SdkVersion,
Regulation: req.Regulation, Regulation: req.Regulation,
CountryCode: req.CountryCode, CountryCode: req.CountryCode,
ConsentMode: req.ConsentMode,
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }

View File

@@ -34,7 +34,6 @@ func TestSnapshotsEqual(t *testing.T) {
PrivacyPolicyURL: &policy, PrivacyPolicyURL: &policy,
CookiePolicyURL: "https://example.com/cookies", CookiePolicyURL: "https://example.com/cookies",
ConsentExpiryDays: 180, ConsentExpiryDays: 180,
ConsentMode: "OPT_IN",
DefaultLanguage: "en", DefaultLanguage: "en",
Categories: []coredata.CookieBannerVersionSnapshotCategory{ Categories: []coredata.CookieBannerVersionSnapshotCategory{
{ {
@@ -248,7 +247,6 @@ func TestBuildSnapshot_RankInvariant(t *testing.T) {
ID: bannerID, ID: bannerID,
CookiePolicyURL: "https://example.com/cookies", CookiePolicyURL: "https://example.com/cookies",
ConsentExpiryDays: 365, ConsentExpiryDays: 365,
ConsentMode: coredata.CookieConsentModeOptIn,
DefaultLanguage: "en", DefaultLanguage: "en",
} }
@@ -298,14 +296,15 @@ func TestRemapTextsForConsentMode(t *testing.T) {
} }
} }
t.Run("no regulation clears reject and customize", func(t *testing.T) { t.Run("opt in mode keeps all buttons", func(t *testing.T) {
t.Parallel() t.Parallel()
texts := baseTexts() texts := baseTexts()
remapTextsForConsentMode(texts, ConsentModeOptIn, RegulationNone) remapTextsForConsentMode(texts, ConsentModeOptIn)
assert.Empty(t, texts["button_reject_all"]) assert.Equal(t, "Accept All", texts["button_accept_all"])
assert.Empty(t, texts["button_customize"]) assert.Equal(t, "Reject All", texts["button_reject_all"])
assert.Equal(t, "Customize", texts["button_customize"])
}) })
t.Run("opt out mode maps opt out to reject and clears customize", func(t *testing.T) { t.Run("opt out mode maps opt out to reject and clears customize", func(t *testing.T) {
@@ -313,7 +312,7 @@ func TestRemapTextsForConsentMode(t *testing.T) {
texts := baseTexts() texts := baseTexts()
texts["button_opt_out"] = "Do Not Sell" texts["button_opt_out"] = "Do Not Sell"
remapTextsForConsentMode(texts, ConsentModeOptOut, RegulationCCPA) remapTextsForConsentMode(texts, ConsentModeOptOut)
assert.Equal(t, "Do Not Sell", texts["button_reject_all"]) assert.Equal(t, "Do Not Sell", texts["button_reject_all"])
assert.Empty(t, texts["button_customize"]) assert.Empty(t, texts["button_customize"])

View File

@@ -116,7 +116,6 @@ func buildSnapshot(
PrivacyPolicyURL: banner.PrivacyPolicyURL, PrivacyPolicyURL: banner.PrivacyPolicyURL,
CookiePolicyURL: banner.CookiePolicyURL, CookiePolicyURL: banner.CookiePolicyURL,
ConsentExpiryDays: banner.ConsentExpiryDays, ConsentExpiryDays: banner.ConsentExpiryDays,
ConsentMode: string(banner.ConsentMode),
DefaultLanguage: banner.DefaultLanguage, DefaultLanguage: banner.DefaultLanguage,
Categories: snapshotCategories, Categories: snapshotCategories,
} }

View File

@@ -38,7 +38,6 @@ type (
PrivacyPolicyURL *string `db:"privacy_policy_url"` PrivacyPolicyURL *string `db:"privacy_policy_url"`
CookiePolicyURL string `db:"cookie_policy_url"` CookiePolicyURL string `db:"cookie_policy_url"`
ConsentExpiryDays int `db:"consent_expiry_days"` ConsentExpiryDays int `db:"consent_expiry_days"`
ConsentMode CookieConsentMode `db:"consent_mode"`
ShowBranding bool `db:"show_branding"` ShowBranding bool `db:"show_branding"`
DefaultLanguage string `db:"default_language"` DefaultLanguage string `db:"default_language"`
PatternAnalysisRequestedAt *time.Time `db:"pattern_analysis_requested_at"` PatternAnalysisRequestedAt *time.Time `db:"pattern_analysis_requested_at"`
@@ -89,7 +88,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -142,7 +140,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -196,7 +193,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -254,7 +250,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -305,7 +300,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -392,7 +386,6 @@ INSERT INTO cookie_banners (
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,
@@ -408,7 +401,6 @@ INSERT INTO cookie_banners (
@privacy_policy_url, @privacy_policy_url,
@cookie_policy_url, @cookie_policy_url,
@consent_expiry_days, @consent_expiry_days,
@consent_mode,
@show_branding, @show_branding,
@default_language, @default_language,
@pattern_analysis_requested_at, @pattern_analysis_requested_at,
@@ -427,7 +419,6 @@ INSERT INTO cookie_banners (
"privacy_policy_url": b.PrivacyPolicyURL, "privacy_policy_url": b.PrivacyPolicyURL,
"cookie_policy_url": b.CookiePolicyURL, "cookie_policy_url": b.CookiePolicyURL,
"consent_expiry_days": b.ConsentExpiryDays, "consent_expiry_days": b.ConsentExpiryDays,
"consent_mode": b.ConsentMode,
"show_branding": b.ShowBranding, "show_branding": b.ShowBranding,
"default_language": b.DefaultLanguage, "default_language": b.DefaultLanguage,
"pattern_analysis_requested_at": b.PatternAnalysisRequestedAt, "pattern_analysis_requested_at": b.PatternAnalysisRequestedAt,
@@ -461,7 +452,6 @@ SET
privacy_policy_url = @privacy_policy_url, privacy_policy_url = @privacy_policy_url,
cookie_policy_url = @cookie_policy_url, cookie_policy_url = @cookie_policy_url,
consent_expiry_days = @consent_expiry_days, consent_expiry_days = @consent_expiry_days,
consent_mode = @consent_mode,
show_branding = @show_branding, show_branding = @show_branding,
default_language = @default_language, default_language = @default_language,
updated_at = @updated_at updated_at = @updated_at
@@ -479,7 +469,6 @@ WHERE
"privacy_policy_url": b.PrivacyPolicyURL, "privacy_policy_url": b.PrivacyPolicyURL,
"cookie_policy_url": b.CookiePolicyURL, "cookie_policy_url": b.CookiePolicyURL,
"consent_expiry_days": b.ConsentExpiryDays, "consent_expiry_days": b.ConsentExpiryDays,
"consent_mode": b.ConsentMode,
"show_branding": b.ShowBranding, "show_branding": b.ShowBranding,
"default_language": b.DefaultLanguage, "default_language": b.DefaultLanguage,
"updated_at": b.UpdatedAt, "updated_at": b.UpdatedAt,
@@ -581,7 +570,6 @@ SELECT
privacy_policy_url, privacy_policy_url,
cookie_policy_url, cookie_policy_url,
consent_expiry_days, consent_expiry_days,
consent_mode,
show_branding, show_branding,
default_language, default_language,
pattern_analysis_requested_at, pattern_analysis_requested_at,

View File

@@ -33,7 +33,6 @@ type (
PrivacyPolicyURL *string `json:"privacy_policy_url,omitempty"` PrivacyPolicyURL *string `json:"privacy_policy_url,omitempty"`
CookiePolicyURL string `json:"cookie_policy_url"` CookiePolicyURL string `json:"cookie_policy_url"`
ConsentExpiryDays int `json:"consent_expiry_days"` ConsentExpiryDays int `json:"consent_expiry_days"`
ConsentMode string `json:"consent_mode"`
DefaultLanguage string `json:"default_language"` DefaultLanguage string `json:"default_language"`
Categories []CookieBannerVersionSnapshotCategory `json:"categories"` Categories []CookieBannerVersionSnapshotCategory `json:"categories"`
} }

View File

@@ -42,6 +42,7 @@ type (
SdkVersion string `db:"sdk_version"` SdkVersion string `db:"sdk_version"`
Regulation *Regulation `db:"regulation"` Regulation *Regulation `db:"regulation"`
CountryCode *CountryCode `db:"country_code"` CountryCode *CountryCode `db:"country_code"`
ConsentMode *CookieConsentMode `db:"consent_mode"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
} }
@@ -94,6 +95,7 @@ SELECT
sdk_version, sdk_version,
regulation, regulation,
country_code, country_code,
consent_mode,
created_at created_at
FROM FROM
cookie_consent_records cookie_consent_records
@@ -180,6 +182,7 @@ INSERT INTO cookie_consent_records (
sdk_version, sdk_version,
regulation, regulation,
country_code, country_code,
consent_mode,
created_at created_at
) VALUES ( ) VALUES (
@id, @id,
@@ -195,6 +198,7 @@ INSERT INTO cookie_consent_records (
@sdk_version, @sdk_version,
@regulation, @regulation,
@country_code, @country_code,
@consent_mode,
@created_at @created_at
) )
` `
@@ -213,6 +217,7 @@ INSERT INTO cookie_consent_records (
"sdk_version": r.SdkVersion, "sdk_version": r.SdkVersion,
"regulation": r.Regulation, "regulation": r.Regulation,
"country_code": r.CountryCode, "country_code": r.CountryCode,
"consent_mode": r.ConsentMode,
"created_at": r.CreatedAt, "created_at": r.CreatedAt,
} }
@@ -244,6 +249,7 @@ SELECT
sdk_version, sdk_version,
regulation, regulation,
country_code, country_code,
consent_mode,
created_at created_at
FROM FROM
cookie_consent_records cookie_consent_records
@@ -297,6 +303,7 @@ SELECT
sdk_version, sdk_version,
regulation, regulation,
country_code, country_code,
consent_mode,
created_at created_at
FROM FROM
cookie_consent_records cookie_consent_records

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_consent_records ADD COLUMN consent_mode cookie_consent_mode;
ALTER TABLE cookie_banners DROP COLUMN consent_mode;

View File

@@ -440,7 +440,6 @@ func (r *mutationResolver) CreateCookieBanner(ctx context.Context, input types.C
PrivacyPolicyURL: input.PrivacyPolicyURL, PrivacyPolicyURL: input.PrivacyPolicyURL,
CookiePolicyURL: input.CookiePolicyURL, CookiePolicyURL: input.CookiePolicyURL,
ConsentExpiryDays: input.ConsentExpiryDays, ConsentExpiryDays: input.ConsentExpiryDays,
ConsentMode: input.ConsentMode,
}, },
) )
if err != nil { if err != nil {
@@ -476,7 +475,6 @@ func (r *mutationResolver) UpdateCookieBanner(ctx context.Context, input types.U
PrivacyPolicyURL: input.PrivacyPolicyURL, PrivacyPolicyURL: input.PrivacyPolicyURL,
CookiePolicyURL: input.CookiePolicyURL, CookiePolicyURL: input.CookiePolicyURL,
ConsentExpiryDays: input.ConsentExpiryDays, ConsentExpiryDays: input.ConsentExpiryDays,
ConsentMode: input.ConsentMode,
DefaultLanguage: input.DefaultLanguage, DefaultLanguage: input.DefaultLanguage,
}, },
) )

View File

@@ -120,7 +120,6 @@ type CookieBanner implements Node {
privacyPolicyUrl: String privacyPolicyUrl: String
cookiePolicyUrl: String! cookiePolicyUrl: String!
consentExpiryDays: Int! consentExpiryDays: Int!
consentMode: CookieConsentMode!
showBranding: Boolean! showBranding: Boolean!
defaultLanguage: String! defaultLanguage: String!
@@ -528,7 +527,6 @@ input CreateCookieBannerInput {
privacyPolicyUrl: String privacyPolicyUrl: String
cookiePolicyUrl: String! cookiePolicyUrl: String!
consentExpiryDays: Int! consentExpiryDays: Int!
consentMode: CookieConsentMode!
} }
input UpdateCookieBannerInput { input UpdateCookieBannerInput {
@@ -537,7 +535,6 @@ input UpdateCookieBannerInput {
privacyPolicyUrl: String privacyPolicyUrl: String
cookiePolicyUrl: String cookiePolicyUrl: String
consentExpiryDays: Int consentExpiryDays: Int
consentMode: CookieConsentMode
defaultLanguage: String defaultLanguage: String
} }

View File

@@ -72,7 +72,6 @@ func NewCookieBanner(b *coredata.CookieBanner) *CookieBanner {
PrivacyPolicyURL: b.PrivacyPolicyURL, PrivacyPolicyURL: b.PrivacyPolicyURL,
CookiePolicyURL: b.CookiePolicyURL, CookiePolicyURL: b.CookiePolicyURL,
ConsentExpiryDays: b.ConsentExpiryDays, ConsentExpiryDays: b.ConsentExpiryDays,
ConsentMode: b.ConsentMode,
ShowBranding: b.ShowBranding, ShowBranding: b.ShowBranding,
DefaultLanguage: b.DefaultLanguage, DefaultLanguage: b.DefaultLanguage,
CreatedAt: b.CreatedAt, CreatedAt: b.CreatedAt,

View File

@@ -180,12 +180,17 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) {
sdkVersion := r.Header.Get("X-SDK-Version") sdkVersion := r.Header.Get("X-SDK-Version")
cc := h.resolveCountryCode(r) cc := h.resolveCountryCode(r)
var regulation *cookiebanner.Regulation var (
regulation *cookiebanner.Regulation
resolvedRegulation cookiebanner.Regulation
)
if cc != nil { if cc != nil {
r := cookiebanner.RegulationForCountry(*cc) resolvedRegulation = cookiebanner.RegulationForCountry(*cc)
regulation = &r regulation = &resolvedRegulation
} }
cm := coredata.CookieConsentMode(cookiebanner.ConsentModeForRegulation(resolvedRegulation))
req := cookiebanner.RecordConsentRequest{ req := cookiebanner.RecordConsentRequest{
Version: body.Version, Version: body.Version,
VisitorID: body.VisitorID, VisitorID: body.VisitorID,
@@ -196,6 +201,7 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) {
SdkVersion: sdkVersion, SdkVersion: sdkVersion,
Regulation: regulation, Regulation: regulation,
CountryCode: cc, CountryCode: cc,
ConsentMode: &cm,
} }
record, err := h.cookieBannerSvc.RecordConsent(r.Context(), bannerID, req) record, err := h.cookieBannerSvc.RecordConsent(r.Context(), bannerID, req)

View File

@@ -4720,7 +4720,6 @@ func (r *Resolver) AddCookieBannerTool(ctx context.Context, req *mcp.CallToolReq
PrivacyPolicyURL: input.PrivacyPolicyURL, PrivacyPolicyURL: input.PrivacyPolicyURL,
CookiePolicyURL: input.CookiePolicyURL, CookiePolicyURL: input.CookiePolicyURL,
ConsentExpiryDays: input.ConsentExpiryDays, ConsentExpiryDays: input.ConsentExpiryDays,
ConsentMode: coredata.CookieConsentMode(input.ConsentMode),
}) })
if err != nil { if err != nil {
return nil, types.AddCookieBannerOutput{}, fmt.Errorf("cannot create cookie banner: %w", err) return nil, types.AddCookieBannerOutput{}, fmt.Errorf("cannot create cookie banner: %w", err)
@@ -4745,10 +4744,6 @@ func (r *Resolver) UpdateCookieBannerTool(ctx context.Context, req *mcp.CallTool
if v := UnwrapOmittable(input.ConsentExpiryDays); v != nil && *v != nil { if v := UnwrapOmittable(input.ConsentExpiryDays); v != nil && *v != nil {
updateReq.ConsentExpiryDays = *v updateReq.ConsentExpiryDays = *v
} }
if v := UnwrapOmittable(input.ConsentMode); v != nil && *v != nil {
mode := coredata.CookieConsentMode(**v)
updateReq.ConsentMode = &mode
}
if v := UnwrapOmittable(input.DefaultLanguage); v != nil && *v != nil { if v := UnwrapOmittable(input.DefaultLanguage); v != nil && *v != nil {
updateReq.DefaultLanguage = *v updateReq.DefaultLanguage = *v
} }

View File

@@ -9311,7 +9311,6 @@ components:
- state - state
- cookie_policy_url - cookie_policy_url
- consent_expiry_days - consent_expiry_days
- consent_mode
- show_branding - show_branding
- default_language - default_language
- created_at - created_at
@@ -9344,10 +9343,6 @@ components:
consent_expiry_days: consent_expiry_days:
type: integer type: integer
description: Days until consent expires description: Days until consent expires
consent_mode:
type: string
enum: [OPT_IN, OPT_OUT]
description: Consent mode
show_branding: show_branding:
type: boolean type: boolean
description: Whether to show Probo branding description: Whether to show Probo branding
@@ -9726,7 +9721,6 @@ components:
- origin - origin
- cookie_policy_url - cookie_policy_url
- consent_expiry_days - consent_expiry_days
- consent_mode
properties: properties:
organization_id: organization_id:
$ref: "#/components/schemas/GID" $ref: "#/components/schemas/GID"
@@ -9746,10 +9740,6 @@ components:
consent_expiry_days: consent_expiry_days:
type: integer type: integer
description: Days until consent expires description: Days until consent expires
consent_mode:
type: string
enum: [OPT_IN, OPT_OUT]
description: Consent mode
AddCookieBannerOutput: AddCookieBannerOutput:
type: object type: object
@@ -9787,11 +9777,6 @@ components:
- integer - integer
- "null" - "null"
go.probo.inc/mcpgen/omittable: true go.probo.inc/mcpgen/omittable: true
consent_mode:
type:
- string
- "null"
go.probo.inc/mcpgen/omittable: true
default_language: default_language:
type: type:
- string - string

View File

@@ -29,7 +29,6 @@ func NewCookieBanner(b *coredata.CookieBanner) *CookieBanner {
PrivacyPolicyURL: b.PrivacyPolicyURL, PrivacyPolicyURL: b.PrivacyPolicyURL,
CookiePolicyURL: b.CookiePolicyURL, CookiePolicyURL: b.CookiePolicyURL,
ConsentExpiryDays: b.ConsentExpiryDays, ConsentExpiryDays: b.ConsentExpiryDays,
ConsentMode: CookieBannerConsentMode(b.ConsentMode),
ShowBranding: b.ShowBranding, ShowBranding: b.ShowBranding,
DefaultLanguage: b.DefaultLanguage, DefaultLanguage: b.DefaultLanguage,
CreatedAt: b.CreatedAt, CreatedAt: b.CreatedAt,