feat: add consent

This commit is contained in:
Kevin Franklin Kim 2024-11-20 09:30:12 +01:00
parent fe5b8c9f0f
commit 615b57f387
No known key found for this signature in database
5 changed files with 58 additions and 6 deletions

View File

@ -99,7 +99,7 @@ func TestMPv2MessageHandler(t *testing.T) {
var done atomic.Bool
router.AddHandler("gtag", "in", pubSub, "out", pubSub, gtag.MPv2MessageHandler)
router.AddNoPublisherHandler("mpv2", "out", pubSub, func(msg *message.Message) error {
expected := `{"client_id":"C123456","events":[{"name":"add_to_cart","params":{}}],"debug_mode":true}`
expected := `{"client_id":"C123456","consent":{"ad_user_data":"GRANTED","ad_personalization":"GRANTED","analytics_storage":"GRANTED"},"events":[{"name":"add_to_cart","params":{"page_location":"https://foomo.org","page_title":"Home"}}],"debug_mode":true}`
if !assert.JSONEq(t, expected, string(msg.Payload)) {
fmt.Println(string(msg.Payload))
}

View File

@ -1,9 +1,11 @@
package gtag
import (
"slices"
"strings"
)
// See https://developers.google.com/tag-platform/security/concepts/consent-mode
type Consent struct {
// Current Google Consent Status. Format 'G1'+'AdsStorageBoolStatus'`+'AnalyticsStorageBoolStatus'
// Example: G101
@ -17,6 +19,11 @@ type Consent struct {
// Will be added with the value "1" if the Google Consent had a default value before getting an update
// Example: G111
GoogleConsentDefault *string `json:"google_consent_default,omitempty" gtag:"gcd,omitempty"`
// Example: 1
// DigitalMarketAct *string `json:"digital_market_act,omitempty" gtag:"dma,omitempty"`
// Example: sypham
// DigitalMarketActParameters *string `json:"digital_market_act_parameters,omitempty" gtag:"dma_cps,omitempty"`
// Example: noapi | denied
}
// ------------------------------------------------------------------------------------------------
@ -24,6 +31,12 @@ type Consent struct {
// ------------------------------------------------------------------------------------------------
func (c Consent) AdStorage() bool {
if c.GoogleConsentDefault != nil {
gcd := strings.Split(*c.GoogleConsentDefault, "")
if len(gcd) > 3 {
return slices.Contains([]string{"l", "t", "r", "n", "u", "v"}, gcd[2])
}
}
if c.GoogleConsentUpdate != nil {
gcs := *c.GoogleConsentUpdate
if strings.HasPrefix(gcs, "G1") && len(gcs) == 4 {
@ -35,6 +48,12 @@ func (c Consent) AdStorage() bool {
}
func (c Consent) AnalyticsStorage() bool {
if c.GoogleConsentDefault != nil {
gcd := strings.Split(*c.GoogleConsentDefault, "")
if len(gcd) > 5 {
return slices.Contains([]string{"l", "t", "r", "n", "u", "v"}, gcd[4])
}
}
if c.GoogleConsentUpdate != nil {
gcs := *c.GoogleConsentUpdate
if strings.HasPrefix(gcs, "G1") && len(gcs) == 4 {
@ -44,3 +63,23 @@ func (c Consent) AnalyticsStorage() bool {
}
return true
}
func (c Consent) AdUserData() bool {
if c.GoogleConsentDefault != nil {
gcd := strings.Split(*c.GoogleConsentDefault, "")
if len(gcd) > 7 {
return slices.Contains([]string{"l", "t", "r", "n", "u", "v"}, gcd[6])
}
}
return c.AdStorage()
}
func (c Consent) AdPersonalization() bool {
if c.GoogleConsentDefault != nil {
gcd := strings.Split(*c.GoogleConsentDefault, "")
if len(gcd) > 9 {
return slices.Contains([]string{"l", "t", "r", "n", "u", "v"}, gcd[8])
}
}
return c.AdStorage()
}

View File

@ -151,11 +151,6 @@ type Payload struct {
NonPersonalizedAds *string `json:"non_personalized_ads,omitempty" gtag:"npa,omitempty"`
// Example: 1
// ARE *string `json:"are,omitempty" gtag:"are,omitempty"`
// Example: 1
// DigitalMarketAct *string `json:"digital_market_act,omitempty" gtag:"dma,omitempty"`
// Example: sypham
// DigitalMarketActParameters *string `json:"digital_market_act_parameters,omitempty" gtag:"dma_cps,omitempty"`
// Example: noapi | denied
// PrivacySandboxCookieDeprecationLabel *string `json:"privacy_sandbox_cookie_deprecation_label,omitempty" gtag:"pscdl,omitempty"`
// A timestamp measuring the difference between the moment this parameter gets populated and the moment the navigation started on that particular page.
// TFD *string `json:"tfd,omitempty" gtag:"tfd,omitempty"`

View File

@ -7,6 +7,7 @@ import (
"strconv"
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
"github.com/foomo/sesamy-go/pkg/encoding/mpv2"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
@ -26,10 +27,20 @@ func MPv2(source gtag.Payload, target any) error {
targetData := map[string]any{
"client_id": source.ClientID,
"user_id": source.UserID,
"session_id": source.SessionID,
"non_personalized_ads": source.NonPersonalizedAds,
"debug_mode": source.IsDebug,
}
// consent
targetConsentData := map[string]any{
"add_storage": mpv2.ConsentText(source.AdStorage()),
"ad_user_data": mpv2.ConsentText(source.AdUserData()),
"ad_personalization": mpv2.ConsentText(source.AdPersonalization()),
"analytics_storage": mpv2.ConsentText(source.AnalyticsStorage()),
}
targetData["consent"] = targetConsentData
// combine user properties
targetUserProperties := map[string]any{}
if node, ok := sourceData["user_property"].(map[string]string); ok {

View File

@ -6,3 +6,10 @@ const (
ConsentDenied Consent = "DENIED"
ConsentGranted Consent = "GRANTED"
)
func ConsentText(v bool) Consent {
if v {
return ConsentGranted
}
return ConsentDenied
}