diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx index e0b574ee2..225320368 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/consent-records/CookieBannerConsentRecordPage.tsx @@ -147,7 +147,7 @@ export default function CookieBannerConsentRecordPage({ - + {record.userAgent ?? "-"} diff --git a/pkg/cmd/consent-record/list/list.go b/pkg/cmd/consent-record/list/list.go index eb490d856..b68e4770c 100644 --- a/pkg/cmd/consent-record/list/list.go +++ b/pkg/cmd/consent-record/list/list.go @@ -52,13 +52,13 @@ query($id: ID!, $first: Int, $after: CursorKey, $filter: CookieConsentRecordFilt ` type consentRecord struct { - ID string `json:"id"` - VisitorID string `json:"visitorId"` - Action string `json:"action"` - SDKVersion string `json:"sdkVersion"` - Regulation string `json:"regulation"` - CountryCode string `json:"countryCode"` - CreatedAt string `json:"createdAt"` + ID string `json:"id"` + VisitorID string `json:"visitorId"` + Action string `json:"action"` + SDKVersion string `json:"sdkVersion"` + Regulation *string `json:"regulation"` + CountryCode *string `json:"countryCode"` + CreatedAt string `json:"createdAt"` } func NewCmdList(f *cmdutil.Factory) *cobra.Command { @@ -154,7 +154,15 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command { rows := make([][]string, 0, len(records)) for _, r := range records { - rows = append(rows, []string{r.ID, r.VisitorID, r.Action, r.SDKVersion, r.Regulation, r.CountryCode, r.CreatedAt}) + regulation := "-" + if r.Regulation != nil { + regulation = *r.Regulation + } + countryCode := "-" + if r.CountryCode != nil { + countryCode = *r.CountryCode + } + rows = append(rows, []string{r.ID, r.VisitorID, r.Action, r.SDKVersion, regulation, countryCode, r.CreatedAt}) } t := cmdutil.NewTable("ID", "VISITOR ID", "ACTION", "SDK VERSION", "REGULATION", "COUNTRY", "CREATED AT").Rows(rows...) diff --git a/pkg/cmd/consent-record/view/view.go b/pkg/cmd/consent-record/view/view.go index 2b24b0622..79bba9704 100644 --- a/pkg/cmd/consent-record/view/view.go +++ b/pkg/cmd/consent-record/view/view.go @@ -54,8 +54,8 @@ type viewResponse struct { ConsentData string `json:"consentData"` Action string `json:"action"` SdkVersion string `json:"sdkVersion"` - Regulation string `json:"regulation"` - CountryCode string `json:"countryCode"` + Regulation *string `json:"regulation"` + CountryCode *string `json:"countryCode"` CreatedAt string `json:"createdAt"` } `json:"node"` } @@ -119,8 +119,12 @@ func NewCmdView(f *cmdutil.Factory) *cobra.Command { _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Visitor ID:"), v.VisitorID) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Action:"), v.Action) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("SDK Version:"), v.SdkVersion) - _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Regulation:"), v.Regulation) - _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Country Code:"), v.CountryCode) + if v.Regulation != nil { + _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Regulation:"), *v.Regulation) + } + if v.CountryCode != nil { + _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Country Code:"), *v.CountryCode) + } if v.IPAddress != nil && *v.IPAddress != "" { _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("IP Address:"), *v.IPAddress) } diff --git a/pkg/cookiebanner/service.go b/pkg/cookiebanner/service.go index 8b11ef51a..e58de21ac 100644 --- a/pkg/cookiebanner/service.go +++ b/pkg/cookiebanner/service.go @@ -103,8 +103,8 @@ type ( ConsentData json.RawMessage Action coredata.CookieConsentAction SdkVersion string - Regulation Regulation - CountryCode coredata.CountryCode + Regulation *Regulation + CountryCode *coredata.CountryCode } DetectedCookie struct { @@ -1847,6 +1847,10 @@ func (s *Service) RecordConsent( CreatedAt: time.Now(), } + if record.Regulation != nil && *record.Regulation == coredata.RegulationNone { + record.Regulation = nil + } + if err := record.Insert(ctx, tx, scope); err != nil { return fmt.Errorf("cannot insert consent record: %w", err) } diff --git a/pkg/coredata/cookie_consent_record.go b/pkg/coredata/cookie_consent_record.go index a3b74f58b..a1bc61591 100644 --- a/pkg/coredata/cookie_consent_record.go +++ b/pkg/coredata/cookie_consent_record.go @@ -40,8 +40,8 @@ type ( ConsentData json.RawMessage `db:"consent_data"` Action CookieConsentAction `db:"action"` SdkVersion string `db:"sdk_version"` - Regulation Regulation `db:"regulation"` - CountryCode CountryCode `db:"country_code"` + Regulation *Regulation `db:"regulation"` + CountryCode *CountryCode `db:"country_code"` CreatedAt time.Time `db:"created_at"` } diff --git a/pkg/coredata/migrations/20260507T143000Z.sql b/pkg/coredata/migrations/20260507T143000Z.sql new file mode 100644 index 000000000..204a00514 --- /dev/null +++ b/pkg/coredata/migrations/20260507T143000Z.sql @@ -0,0 +1,22 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- 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 + ALTER COLUMN regulation DROP NOT NULL; + +ALTER TABLE cookie_consent_records + ALTER COLUMN country_code DROP NOT NULL; + +UPDATE cookie_consent_records SET regulation = NULL WHERE regulation = ''; +UPDATE cookie_consent_records SET country_code = NULL WHERE country_code = ''; diff --git a/pkg/server/api/console/v1/graphql/cookie_consent_record.graphql b/pkg/server/api/console/v1/graphql/cookie_consent_record.graphql index 6b82bdd2f..39bbd42f7 100644 --- a/pkg/server/api/console/v1/graphql/cookie_consent_record.graphql +++ b/pkg/server/api/console/v1/graphql/cookie_consent_record.graphql @@ -130,8 +130,8 @@ type CookieConsentRecord implements Node { consentData: String! action: CookieConsentAction! sdkVersion: String! - regulation: Regulation! - countryCode: CountryCode! + regulation: Regulation + countryCode: CountryCode createdAt: Datetime! } diff --git a/pkg/server/api/cookiebanner/v1/handler.go b/pkg/server/api/cookiebanner/v1/handler.go index fac8b3086..b4b5314f3 100644 --- a/pkg/server/api/cookiebanner/v1/handler.go +++ b/pkg/server/api/cookiebanner/v1/handler.go @@ -72,7 +72,11 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) { lang := r.URL.Query().Get("lang") cc := h.resolveCountryCode(r) - regulation := cookiebanner.RegulationForCountry(cc) + + var regulation cookiebanner.Regulation + if cc != nil { + regulation = cookiebanner.RegulationForCountry(*cc) + } config, err := h.cookieBannerSvc.GetActiveBannerConfig(r.Context(), bannerID, lang, regulation) if err != nil { @@ -92,16 +96,16 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) { httpserver.RenderJSON(w, http.StatusOK, config) } -func (h *Handler) resolveCountryCode(r *http.Request) coredata.CountryCode { +func (h *Handler) resolveCountryCode(r *http.Request) *coredata.CountryCode { ip := clientip.Extract(r) cc, err := h.geolocSvc.LookupCountry(r.Context(), ip) if err != nil { h.logger.ErrorCtx(r.Context(), "cannot resolve country for IP", log.Error(err)) - return "" + return nil } - return cc + return &cc } func (h *Handler) handleGetConsent(w http.ResponseWriter, r *http.Request) { @@ -169,6 +173,12 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) { sdkVersion := r.Header.Get("X-SDK-Version") cc := h.resolveCountryCode(r) + var regulation *cookiebanner.Regulation + if cc != nil { + r := cookiebanner.RegulationForCountry(*cc) + regulation = &r + } + req := cookiebanner.RecordConsentRequest{ Version: body.Version, VisitorID: body.VisitorID, @@ -177,7 +187,7 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) { ConsentData: body.ConsentData, Action: body.Action, SdkVersion: sdkVersion, - Regulation: cookiebanner.RegulationForCountry(cc), + Regulation: regulation, CountryCode: cc, } diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 8419874b6..b1b7220e9 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -9565,8 +9565,6 @@ components: - consent_data - action - sdk_version - - regulation - - country_code - created_at properties: id: @@ -9604,9 +9602,11 @@ components: regulation: $ref: "#/components/schemas/Regulation" description: Applicable regulation + nullable: true country_code: $ref: "#/components/schemas/CountryCode" description: Visitor country code (ISO 3166-1 alpha-2) + nullable: true created_at: type: string format: date-time