Surface regulation and user agent across consent record API layers

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-05-07 14:59:00 +04:00
parent 806bd672ed
commit 5f4fd3c427
9 changed files with 74 additions and 26 deletions

View File

@@ -147,7 +147,7 @@ export default function CookieBannerConsentRecordPage({
</span> </span>
</PropertyRow> </PropertyRow>
<PropertyRow label={__("User Agent")}> <PropertyRow label={__("User Agent")}>
<span className="font-mono text-sm truncate max-w-md" title={record.userAgent ?? undefined}> <span className="font-mono text-sm break-all">
{record.userAgent ?? "-"} {record.userAgent ?? "-"}
</span> </span>
</PropertyRow> </PropertyRow>

View File

@@ -52,13 +52,13 @@ query($id: ID!, $first: Int, $after: CursorKey, $filter: CookieConsentRecordFilt
` `
type consentRecord struct { type consentRecord struct {
ID string `json:"id"` ID string `json:"id"`
VisitorID string `json:"visitorId"` VisitorID string `json:"visitorId"`
Action string `json:"action"` Action string `json:"action"`
SDKVersion string `json:"sdkVersion"` SDKVersion string `json:"sdkVersion"`
Regulation string `json:"regulation"` Regulation *string `json:"regulation"`
CountryCode string `json:"countryCode"` CountryCode *string `json:"countryCode"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
} }
func NewCmdList(f *cmdutil.Factory) *cobra.Command { func NewCmdList(f *cmdutil.Factory) *cobra.Command {
@@ -154,7 +154,15 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
rows := make([][]string, 0, len(records)) rows := make([][]string, 0, len(records))
for _, r := range 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...) t := cmdutil.NewTable("ID", "VISITOR ID", "ACTION", "SDK VERSION", "REGULATION", "COUNTRY", "CREATED AT").Rows(rows...)

View File

@@ -54,8 +54,8 @@ type viewResponse struct {
ConsentData string `json:"consentData"` ConsentData string `json:"consentData"`
Action string `json:"action"` Action string `json:"action"`
SdkVersion string `json:"sdkVersion"` SdkVersion string `json:"sdkVersion"`
Regulation string `json:"regulation"` Regulation *string `json:"regulation"`
CountryCode string `json:"countryCode"` CountryCode *string `json:"countryCode"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
} `json:"node"` } `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("Visitor ID:"), v.VisitorID)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Action:"), v.Action) _, _ = 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("SDK Version:"), v.SdkVersion)
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Regulation:"), v.Regulation) if v.Regulation != nil {
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("Country Code:"), v.CountryCode) _, _ = 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 != "" { if v.IPAddress != nil && *v.IPAddress != "" {
_, _ = fmt.Fprintf(out, "%s%s\n", label.Render("IP Address:"), *v.IPAddress) _, _ = fmt.Fprintf(out, "%s%s\n", label.Render("IP Address:"), *v.IPAddress)
} }

View File

@@ -103,8 +103,8 @@ type (
ConsentData json.RawMessage ConsentData json.RawMessage
Action coredata.CookieConsentAction Action coredata.CookieConsentAction
SdkVersion string SdkVersion string
Regulation Regulation Regulation *Regulation
CountryCode coredata.CountryCode CountryCode *coredata.CountryCode
} }
DetectedCookie struct { DetectedCookie struct {
@@ -1847,6 +1847,10 @@ func (s *Service) RecordConsent(
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }
if record.Regulation != nil && *record.Regulation == coredata.RegulationNone {
record.Regulation = nil
}
if err := record.Insert(ctx, tx, scope); err != nil { if err := record.Insert(ctx, tx, scope); err != nil {
return fmt.Errorf("cannot insert consent record: %w", err) return fmt.Errorf("cannot insert consent record: %w", err)
} }

View File

@@ -40,8 +40,8 @@ type (
ConsentData json.RawMessage `db:"consent_data"` ConsentData json.RawMessage `db:"consent_data"`
Action CookieConsentAction `db:"action"` Action CookieConsentAction `db:"action"`
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"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
} }

View File

@@ -0,0 +1,22 @@
-- 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
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 = '';

View File

@@ -130,8 +130,8 @@ type CookieConsentRecord implements Node {
consentData: String! consentData: String!
action: CookieConsentAction! action: CookieConsentAction!
sdkVersion: String! sdkVersion: String!
regulation: Regulation! regulation: Regulation
countryCode: CountryCode! countryCode: CountryCode
createdAt: Datetime! createdAt: Datetime!
} }

View File

@@ -72,7 +72,11 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) {
lang := r.URL.Query().Get("lang") lang := r.URL.Query().Get("lang")
cc := h.resolveCountryCode(r) 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) config, err := h.cookieBannerSvc.GetActiveBannerConfig(r.Context(), bannerID, lang, regulation)
if err != nil { if err != nil {
@@ -92,16 +96,16 @@ func (h *Handler) handleGetConfig(w http.ResponseWriter, r *http.Request) {
httpserver.RenderJSON(w, http.StatusOK, config) 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) ip := clientip.Extract(r)
cc, err := h.geolocSvc.LookupCountry(r.Context(), ip) cc, err := h.geolocSvc.LookupCountry(r.Context(), ip)
if err != nil { if err != nil {
h.logger.ErrorCtx(r.Context(), "cannot resolve country for IP", log.Error(err)) 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) { 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") sdkVersion := r.Header.Get("X-SDK-Version")
cc := h.resolveCountryCode(r) cc := h.resolveCountryCode(r)
var regulation *cookiebanner.Regulation
if cc != nil {
r := cookiebanner.RegulationForCountry(*cc)
regulation = &r
}
req := cookiebanner.RecordConsentRequest{ req := cookiebanner.RecordConsentRequest{
Version: body.Version, Version: body.Version,
VisitorID: body.VisitorID, VisitorID: body.VisitorID,
@@ -177,7 +187,7 @@ func (h *Handler) handlePostConsent(w http.ResponseWriter, r *http.Request) {
ConsentData: body.ConsentData, ConsentData: body.ConsentData,
Action: body.Action, Action: body.Action,
SdkVersion: sdkVersion, SdkVersion: sdkVersion,
Regulation: cookiebanner.RegulationForCountry(cc), Regulation: regulation,
CountryCode: cc, CountryCode: cc,
} }

View File

@@ -9565,8 +9565,6 @@ components:
- consent_data - consent_data
- action - action
- sdk_version - sdk_version
- regulation
- country_code
- created_at - created_at
properties: properties:
id: id:
@@ -9604,9 +9602,11 @@ components:
regulation: regulation:
$ref: "#/components/schemas/Regulation" $ref: "#/components/schemas/Regulation"
description: Applicable regulation description: Applicable regulation
nullable: true
country_code: country_code:
$ref: "#/components/schemas/CountryCode" $ref: "#/components/schemas/CountryCode"
description: Visitor country code (ISO 3166-1 alpha-2) description: Visitor country code (ISO 3166-1 alpha-2)
nullable: true
created_at: created_at:
type: string type: string
format: date-time format: date-time