mirror of
https://github.com/foomo/sesamy-go.git
synced 2025-10-16 12:35:43 +00:00
refactor: change packages
This commit is contained in:
parent
64c50a6f57
commit
9117669802
232
.golangci.yml
232
.golangci.yml
@ -1,89 +1,201 @@
|
||||
run:
|
||||
skip-dirs:
|
||||
- tmp
|
||||
timeout: 5m
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- 'tmp'
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- forbidigo
|
||||
- forcetypeassert
|
||||
|
||||
linters-settings:
|
||||
# https://golangci-lint.run/usage/linters/#revive
|
||||
revive:
|
||||
rules:
|
||||
- name: indent-error-flow
|
||||
disabled: true
|
||||
- name: exported
|
||||
disabled: true
|
||||
# https://golangci-lint.run/usage/linters/#misspell
|
||||
misspell:
|
||||
mode: restricted
|
||||
# https://golangci-lint.run/usage/linters/#asasalint
|
||||
asasalint:
|
||||
ignore-test: true
|
||||
# https://golangci-lint.run/usage/linters/#exhaustive
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
# https://golangci-lint.run/usage/linters/#predeclared
|
||||
predeclared:
|
||||
ignore: "new,error"
|
||||
# https://golangci-lint.run/usage/linters/#gocritic
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- performance
|
||||
- style
|
||||
disabled-tags:
|
||||
- experimental
|
||||
- opinionated
|
||||
disabled-checks:
|
||||
- ifElseChain
|
||||
settings:
|
||||
hugeParam:
|
||||
sizeThreshold: 512
|
||||
- commentFormatting
|
||||
# https://golangci-lint.run/usage/linters/#testifylint
|
||||
testifylint:
|
||||
disable:
|
||||
- float-compare
|
||||
# https://golangci-lint.run/usage/linters/#gosec
|
||||
gosec:
|
||||
config:
|
||||
G306: "0700"
|
||||
excludes:
|
||||
- G101 # Potential hardcoded credentials
|
||||
- G102 # Bind to all interfaces
|
||||
- G112 # Potential slowloris attack
|
||||
- G401 # Detect the usage of DES, RC4, MD5 or SHA1
|
||||
- G402 # Look for bad TLS connection settings
|
||||
- G404 # Insecure random number source (rand)
|
||||
- G501 # Import blocklist: crypto/md5
|
||||
- G505 # Import blocklist: crypto/sha1
|
||||
confidence: medium
|
||||
# https://golangci-lint.run/usage/linters/#importas
|
||||
importas:
|
||||
no-unaliased: true
|
||||
# https://golangci-lint.run/usage/linters/#gomoddirectives
|
||||
gomoddirectives:
|
||||
replace-local: true
|
||||
# https://golangci-lint.run/usage/linters/#revive
|
||||
revive:
|
||||
ignore-generated-header: true
|
||||
enable-all-rules: true
|
||||
rules:
|
||||
- name: line-length-limit
|
||||
disabled: true
|
||||
- name: cognitive-complexity
|
||||
disabled: true
|
||||
- name: unused-parameter
|
||||
disabled: true
|
||||
- name: add-constant
|
||||
disabled: true
|
||||
- name: cyclomatic
|
||||
disabled: true
|
||||
- name: function-length
|
||||
disabled: true
|
||||
- name: function-result-limit
|
||||
disabled: true
|
||||
- name: flag-parameter
|
||||
disabled: true
|
||||
- name: unused-receiver
|
||||
disabled: true
|
||||
- name: argument-limit
|
||||
disabled: true
|
||||
- name: max-control-nesting
|
||||
disabled: true
|
||||
- name: comment-spacings
|
||||
disabled: true
|
||||
- name: struct-tag
|
||||
arguments:
|
||||
- "json,inline"
|
||||
- name: unhandled-error
|
||||
arguments:
|
||||
- "fmt.Println"
|
||||
- "io.Writer.Write"
|
||||
- "strings.Builder.WriteString"
|
||||
# TODO remove
|
||||
- name: deep-exit
|
||||
disabled: true
|
||||
- name: if-return
|
||||
disabled: true
|
||||
- name: empty-block
|
||||
disabled: true
|
||||
- name: indent-error-flow
|
||||
disabled: true
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
# Enabled by default linters:
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
## Enabled by default linters:
|
||||
- errcheck # errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
|
||||
- gosimple # (megacheck) Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
|
||||
- govet # (vet, vetshadow) Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [fast: false, auto-fix: false]
|
||||
- ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
|
||||
- staticcheck # (megacheck) It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
|
||||
- unused # (megacheck) Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
|
||||
|
||||
# Disabled by default linters:
|
||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
|
||||
## Disabled by your configuration linters:
|
||||
- asasalint # check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false]
|
||||
- asciicheck # checks that all code identifiers does not have non-ASCII symbols in the name [fast: true, auto-fix: false]
|
||||
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
|
||||
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
||||
- bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
|
||||
- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: false, auto-fix: false]
|
||||
- contextcheck # check whether the function uses a non-inherited context [fast: false, auto-fix: false]
|
||||
#- copyloopvar # (go >= 1.22) copyloopvar is a linter detects places where loop variables are copied [fast: true, auto-fix: false]
|
||||
- decorder # check declaration order and count of types, constants, variables and functions [fast: true, auto-fix: false]
|
||||
- durationcheck # check for two durations multiplied together [fast: false, auto-fix: false]
|
||||
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
|
||||
- errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false]
|
||||
- errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false]
|
||||
- exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false]
|
||||
- exportloopref # checks for pointers to enclosing loop variables [fast: false, auto-fix: false]
|
||||
#- forbidigo # Forbids identifiers [fast: false, auto-fix: false]
|
||||
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
|
||||
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
||||
- gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid. [fast: true, auto-fix: false]
|
||||
- gochecksumtype # Run exhaustiveness checks on Go "sum types" [fast: false, auto-fix: false]
|
||||
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
|
||||
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
|
||||
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true]
|
||||
#- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
|
||||
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: true]
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
|
||||
- goheader # Checks is file header matches to pattern [fast: true, auto-fix: true]
|
||||
- goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. [fast: true, auto-fix: true]
|
||||
- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
|
||||
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
|
||||
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
||||
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end. [fast: true, auto-fix: false]
|
||||
- gosec # (gas) Inspects source code for security problems [fast: false, auto-fix: false]
|
||||
- gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase [fast: false, auto-fix: false]
|
||||
- grouper # Analyze expression groups. [fast: true, auto-fix: false]
|
||||
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
||||
#- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||
- inamedparam # reports interfaces with unnamed method parameters [fast: true, auto-fix: false]
|
||||
#- intrange # (go >= 1.22) intrange is a linter to find places where for loops could make use of an integer range. [fast: true, auto-fix: false]
|
||||
- loggercheck # (logrlint) Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). [fast: false, auto-fix: false]
|
||||
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
||||
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
||||
#- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
|
||||
- misspell # Finds commonly misspelled English words [fast: true, auto-fix: true]
|
||||
- mirror # reports wrong mirror patterns of bytes/strings usage [fast: false, auto-fix: true]
|
||||
- musttag # enforce field tags in (un)marshaled structs [fast: false, auto-fix: false]
|
||||
- nakedret # Checks that functions with naked returns are not longer than a maximum size (can be zero). [fast: true, auto-fix: false]
|
||||
- nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
|
||||
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
|
||||
- noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false]
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
|
||||
- noctx # Finds sending http request without context.Context [fast: false, auto-fix: false]
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: true]
|
||||
- nonamedreturns # Reports all named returns [fast: false, auto-fix: false]
|
||||
- nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false]
|
||||
- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
|
||||
#- paralleltest # Detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false]
|
||||
- predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
|
||||
- promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
|
||||
- reassign # Checks that package variables are not reassigned [fast: false, auto-fix: false]
|
||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
|
||||
#- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
|
||||
- rowserrcheck # checks whether Rows.Err of rows is checked successfully [fast: false, auto-fix: false]
|
||||
- spancheck # Checks for mistakes with OpenTelemetry/Census spans. [fast: false, auto-fix: false]
|
||||
- sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed. [fast: false, auto-fix: false]
|
||||
- stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false]
|
||||
- tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false]
|
||||
- testableexamples # linter checks if examples are testable (have an expected output) [fast: true, auto-fix: false]
|
||||
- testifylint # Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false]
|
||||
- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
|
||||
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
|
||||
- thelper # thelper detects tests helpers which is not start with t.Helper() method. [fast: false, auto-fix: false]
|
||||
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes. [fast: false, auto-fix: false]
|
||||
- unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false]
|
||||
- unparam # Reports unused function parameters [fast: false, auto-fix: false]
|
||||
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false]
|
||||
- wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
|
||||
- whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
|
||||
disable:
|
||||
- unused
|
||||
- wastedassign # Finds wasted assignment statements [fast: false, auto-fix: false]
|
||||
- whitespace # Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc. [fast: true, auto-fix: true]
|
||||
|
||||
## Don't enable
|
||||
#- cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false]
|
||||
#- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
||||
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
||||
#- dupword # checks for duplicate words in the source code [fast: true, auto-fix: false]
|
||||
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
|
||||
#- err113 # Go linter to check the errors handling expressions [fast: false, auto-fix: false]
|
||||
#- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false]
|
||||
#- gci # Gci controls Go package import order and makes it always deterministic. [fast: true, auto-fix: true]
|
||||
#- gochecknoglobals # Check that no global variables exist. [fast: false, auto-fix: false]
|
||||
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
||||
#- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
|
||||
#- godot # Check if comments end in a period [fast: true, auto-fix: true]
|
||||
#- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
|
||||
#- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
|
||||
#- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
|
||||
#- ginkgolinter # enforces standards of using ginkgo and gomega [fast: false, auto-fix: false]
|
||||
#- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
|
||||
#- interfacebloat # A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false]
|
||||
#- lll # Reports long lines [fast: true, auto-fix: false]
|
||||
#- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
|
||||
#- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||
#- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
|
||||
#- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
|
||||
#- perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative. [fast: false, auto-fix: false]
|
||||
#- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
|
||||
#- protogetter # Reports direct reads from proto message fields when getters should be used [fast: false, auto-fix: true]
|
||||
#- sloglint # ensure consistent code style when using log/slog [fast: false, auto-fix: false]
|
||||
#- tagalign # check that struct tags are well aligned [fast: true, auto-fix: true]
|
||||
#- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
|
||||
#- unparam # Reports unused function parameters [fast: false, auto-fix: false]
|
||||
#- varnamelen # checks that the length of a variable's name matches its scope [fast: false, auto-fix: false]
|
||||
#- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
|
||||
#- wsl # add or remove empty lines [fast: true, auto-fix: false]
|
||||
#- zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false]
|
||||
|
||||
@ -141,6 +141,7 @@ func (c *Client) SendRawEvent(r *http.Request, event *Payload) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to send request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var body string
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/foomo/sesamy-go/protocol/gtag"
|
||||
"github.com/foomo/sesamy-go/encoding/gtag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -20,17 +20,17 @@ func TestDecode(t *testing.T) {
|
||||
{
|
||||
name: "page_view",
|
||||
args: "v=2&tid=G-123456>m=45je42s0v893689383z8894072534za200&_p=1709286636310&gcd=13l3l3l3l1&npa=0&dma_cps=sypham&dma=1&cid=292234677.1707898933&ul=en-us&sr=3840x1600&uaa=arm&uab=64&uafvl=Chromium&uamb=0&uam=&uap=macOS&uapv=14.3.1&uaw=0&are=1&pae=1&pscdl=noapi&_s=1&sid=1709286452&sct=7&seg=1&dl=https%3A%2F%2Fwww.homemade.ch%2Fprodukt%2Fkuhn-rikon-wiegemesser-900047100%3Fid%3D900047100&dr=https%3A%2F%2Fwww.homemade.ch%2Fmesser-besteck&dt=Wiegemesser&en=page_view&tfd=5682",
|
||||
want: `{"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v893689383z8894072534za200","client_id":"292234677.1707898933","client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0"},"document_location":"https://www.homemade.ch/produkt/kuhn-rikon-wiegemesser-900047100?id=900047100","document_title":"Wiegemesser","document_referrer":"https://www.homemade.ch/messer-besteck","event_name":"page_view","session_id":"1709286452","ecommerce":{}}`,
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l3l1"},"campaign":{},"ecommerce":{},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0"},"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v893689383z8894072534za200","client_id":"292234677.1707898933","document_location":"https://www.homemade.ch/produkt/kuhn-rikon-wiegemesser-900047100?id=900047100","document_title":"Wiegemesser","document_referrer":"https://www.homemade.ch/messer-besteck","event_name":"page_view","session_id":"1709286452","non_personalized_ads":"0"}`,
|
||||
},
|
||||
{
|
||||
name: "add_to_cart",
|
||||
args: "v=2&tid=G-123456>m=45je42s0v9175354889z89175348963za200&_p=1709297934217&_dbg=1&gcd=13l3l3l3l1&npa=0&dma_cps=sypham&dma=1&cid=1220643501.1708014725&ul=en-us&sr=3840x1600&_fplc=0&ur=DE-BY&uaa=arm&uab=64&uafvl=Chromium&uamb=0&uam=&uap=macOS&uapv=14.3.1&uaw=0&are=1&pscdl=noapi&_eu=IA&sst.uc=DE&sst.etld=google.de&sst.gcsub=region1&sst.gcd=13l3l3l3l1&sst.tft=1709297934217&_s=8&cu=USD&sid=1709296380&sct=7&seg=1&dl=https%3A%2F%2Fsniffer.cloud.bestbytes.net%2F%3Fgtm_debug%3D1709297933868&dr=https%3A%2F%2Ftagassistant.google.com%2F&dt=Server%20Side%20Tracking%20Prototype%20(codename%3A%20sniffer)&en=add_to_cart&pr1=idSKU_12345~nmStan%20and%20Friends%20Tee~afGoogle%20Store~cpSUMMER_FUN~ds2.22~lp5~brGoogle~caApparel~c2Adult~c3Shirts~c4Crew~c5Short%20sleeve~lirelated_products~lnRelated%20products~vagreen~loChIJIQBpAG2ahYAR_6128GcTUEo~pr10.01~qt3&epn.value=30.03&tfd=15129&richsstsse",
|
||||
want: `{"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v9175354889z89175348963za200","client_id":"1220643501.1708014725","richsstsse":"","client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0","user_region":"DE-BY"},"document_location":"https://sniffer.cloud.bestbytes.net/?gtm_debug=1709297933868","document_title":"Server Side Tracking Prototype (codename: sniffer)","document_referrer":"https://tagassistant.google.com/","event_name":"add_to_cart","event_parameter_number":{"value":"30.03"},"session_id":"1709296380","ecommerce":{"currency":"USD","items":[{"item_id":"SKU_12345","item_name":"Stan and Friends Tee","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_variant":"green","price":"10.01","quantity":"3","coupon":"SUMMER_FUN","item_list_name":"Related products","item_list_position":"5","item_list_id":"related_products","discount":"2.22","affiliation":"Google Store","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo"}]},"sst":{"etld":"google.de","gcsub":"region1","uc":"DE","tft":"1709297934217","gcd":"13l3l3l3l1"}}`,
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l3l1"},"campaign":{},"ecommerce":{"currency":"USD","items":[{"affiliation":"Google Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"5","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0","user_region":"DE-BY"},"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v9175354889z89175348963za200","client_id":"1220643501.1708014725","richsstsse":"","document_location":"https://sniffer.cloud.bestbytes.net/?gtm_debug=1709297933868","document_title":"Server Side Tracking Prototype (codename: sniffer)","document_referrer":"https://tagassistant.google.com/","event_name":"add_to_cart","event_parameter_number":{"value":"30.03"},"session_id":"1709296380","non_personalized_ads":"0","sst":{"etld":"google.de","gcsub":"region1","uc":"DE","tft":"1709297934217","gcd":"13l3l3l3l1"}}`,
|
||||
},
|
||||
{
|
||||
name: "select_item",
|
||||
args: "v=2&tid=G-F9XM71K45T>m=45he4580v9184715813z89184708445za200&_p=1715430403224&_dbg=1&gcd=13l3l3l2l1&npa=1&dma_cps=sypham&dma=1&cid=179294588.1715353601&ecid=251283723&ul=en-us&sr=3840x1600&_fplc=0&ur=&uaa=arm&uab=64&uafvl=Chromium%3B124.0.6367.119%7CGoogle%2520Chrome%3B124.0.6367.119%7CNot-A.Brand%3B99.0.0.0&uamb=0&uam=&uap=macOS&uapv=14.4.1&uaw=0&are=1&frm=0&pscdl=noapi&sst.gcd=13l3l3l2l1&sst.tft=1715430403224&sst.ude=0&_s=3&sid=1715428762&sct=2&seg=1&dl=https%3A%2F%2Fsesamy.local.bestbytes.net%2F%3Fgtm_debug%3D1715430402906&dr=https%3A%2F%2Ftagassistant.google.com%2F&dt=Home&en=select_item&pr1=idSKU_12345~nmStan%20and%20Friends%20Tee~afGoogle%20Merchandise%20Store~cpSUMMER_FUN~ds2.22~lp0~brGoogle~caApparel~c2Adult~c3Shirts~c4Crew~c5Short%20sleeve~lirelated_products~lnRelated%20Products~vagreen~loChIJIQBpAG2ahYAR_6128GcTUEo~pr10.01~qt3&ep.enable_page_views=false&ep.item_list_id=related_products&ep.item_list_name=Related%20products&_et=89&tfd=8618&richsstsse",
|
||||
want: `{"protocol_version":"2","tracking_id":"G-F9XM71K45T","gtmhash_info":"45he4580v9184715813z89184708445za200","client_id":"179294588.1715353601","richsstsse":"","client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium;124.0.6367.119|Google Chrome;124.0.6367.119|Not-A.Brand;99.0.0.0","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.4.1","user_agent_wow_64":"0","user_region":""},"document_location":"https://sesamy.local.bestbytes.net/?gtm_debug=1715430402906","document_title":"Home","document_referrer":"https://tagassistant.google.com/","event_name":"select_item","event_parameter":{"enable_page_views":"false","item_list_id":"related_products","item_list_name":"Related products"},"session_id":"1715428762","ecommerce":{"items":[{"item_id":"SKU_12345","item_name":"Stan and Friends Tee","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_variant":"green","price":"10.01","quantity":"3","coupon":"SUMMER_FUN","item_list_name":"Related Products","item_list_position":"0","item_list_id":"related_products","discount":"2.22","affiliation":"Google Merchandise Store","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo"}]},"sst":{"tft":"1715430403224","gcd":"13l3l3l2l1"}}`,
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l2l1"},"campaign":{},"ecommerce":{"items":[{"affiliation":"Google Merchandise Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related Products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"0","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium;124.0.6367.119|Google Chrome;124.0.6367.119|Not-A.Brand;99.0.0.0","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.4.1","user_agent_wow_64":"0","user_region":""},"protocol_version":"2","tracking_id":"G-F9XM71K45T","gtmhash_info":"45he4580v9184715813z89184708445za200","client_id":"179294588.1715353601","richsstsse":"","document_location":"https://sesamy.local.bestbytes.net/?gtm_debug=1715430402906","document_title":"Home","document_referrer":"https://tagassistant.google.com/","event_name":"select_item","event_parameter":{"enable_page_views":"false","item_list_id":"related_products","item_list_name":"Related products"},"session_id":"1715428762","non_personalized_ads":"1","sst":{"tft":"1715430403224","gcd":"13l3l3l2l1"}}`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -41,7 +41,9 @@ func TestDecode(t *testing.T) {
|
||||
out, err := json.Marshal(event)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.want, string(out))
|
||||
if !assert.JSONEq(t, tt.want, string(out)) {
|
||||
t.Log(string(out))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -41,22 +41,13 @@ func Encode(input *Payload) (url.Values, io.Reader, error) {
|
||||
data[s] = a
|
||||
}
|
||||
|
||||
// a, err := json.Marshal(input)
|
||||
// if err != nil {
|
||||
// return nil, nil, errors.Wrap(err, "failed to marshal event")
|
||||
// }
|
||||
//
|
||||
// if err := json.Unmarshal(a, &data); err != nil {
|
||||
// return nil, nil, errors.Wrap(err, "failed to decode into map")
|
||||
// }
|
||||
|
||||
ret := url.Values{}
|
||||
for k, v := range data {
|
||||
switch t := v.(type) {
|
||||
case []interface{}:
|
||||
case []any:
|
||||
for key, value := range t {
|
||||
switch tt := value.(type) {
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
ret[fmt.Sprintf("%s%d", k, key+1)] = []string{EncodeObjectValue(tt)}
|
||||
default:
|
||||
panic("unhandled")
|
||||
@ -66,7 +57,7 @@ func Encode(input *Payload) (url.Values, io.Reader, error) {
|
||||
for key, value := range t {
|
||||
ret[fmt.Sprintf("%s.%s", k, key)] = []string{value}
|
||||
}
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
for key, value := range t {
|
||||
ret[fmt.Sprintf("%s.%s", k, key)] = []string{fmt.Sprintf("%v", value)}
|
||||
}
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/foomo/sesamy-go/protocol/gtag"
|
||||
"github.com/foomo/sesamy-go/encoding/gtag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -1,10 +1,18 @@
|
||||
package gtag
|
||||
|
||||
type Item struct {
|
||||
// Example: 12345
|
||||
ItemID *string `json:"item_id,omitempty" gtag:"id,omitempty"`
|
||||
// Example: Stan and Friends Tee
|
||||
ItemName *string `json:"item_name,omitempty" gtag:"nm,omitempty"`
|
||||
// Example: Foo Marketplace
|
||||
Affiliation *string `json:"affiliation,omitempty" gtag:"af,omitempty"`
|
||||
// Example: 50%OFF
|
||||
Coupon *string `json:"coupon,omitempty" gtag:"cp,omitempty"`
|
||||
// The name of the promotional creative.
|
||||
// Example: summer_banner2
|
||||
CreativeName *string `json:"creative_name,omitempty" gtag:"cn,omitempty"`
|
||||
// The name of the promotional creative slot associated with the item.
|
||||
// Example: featured_app_1
|
||||
CreativeSlot *string `json:"creative_slot,omitempty" gtag:"cs,omitempty"`
|
||||
// Example: 10.00
|
||||
Discount *string `json:"discount,omitempty" gtag:"ds,omitempty"`
|
||||
// Example: Google
|
||||
ItemBrand *string `json:"item_brand,omitempty" gtag:"br,omitempty"`
|
||||
// Example: men
|
||||
@ -17,36 +25,28 @@ type Item struct {
|
||||
ItemCategory4 *string `json:"item_category4,omitempty" gtag:"c4,omitempty"`
|
||||
// Example: men
|
||||
ItemCategory5 *string `json:"item_category5,omitempty" gtag:"c5,omitempty"`
|
||||
// Example: Yellow
|
||||
ItemVariant *string `json:"item_variant,omitempty" gtag:"va,omitempty"`
|
||||
// Example: 123.45
|
||||
Price *string `json:"price,omitempty" gtag:"pr,omitempty"`
|
||||
// Example: 1
|
||||
Quantity *string `json:"quantity,omitempty" gtag:"qt,omitempty"`
|
||||
// Example: 50%OFF
|
||||
Coupon *string `json:"coupon,omitempty" gtag:"cp,omitempty"`
|
||||
// Example: cross-selling: mens
|
||||
ItemListName *string `json:"item_list_name,omitempty" gtag:"ln,omitempty"`
|
||||
// Example: 10
|
||||
ItemListPosition *string `json:"item_list_position,omitempty" gtag:"lp,omitempty"`
|
||||
// Example: 12345
|
||||
ItemID *string `json:"item_id,omitempty" gtag:"id,omitempty"`
|
||||
// Example: id-mens-123
|
||||
ItemListID *string `json:"item_list_id,omitempty" gtag:"li,omitempty"`
|
||||
// Example: 10.00
|
||||
Discount *string `json:"discount,omitempty" gtag:"ds,omitempty"`
|
||||
// Example: Foo Marketplace
|
||||
Affiliation *string `json:"affiliation,omitempty" gtag:"af,omitempty"`
|
||||
// Example: cross-selling: mens
|
||||
ItemListName *string `json:"item_list_name,omitempty" gtag:"ln,omitempty"`
|
||||
// Example: Stan and Friends Tee
|
||||
ItemName *string `json:"item_name,omitempty" gtag:"nm,omitempty"`
|
||||
// Example: Yellow
|
||||
ItemVariant *string `json:"item_variant,omitempty" gtag:"va,omitempty"`
|
||||
// Example: 10 FIXME
|
||||
ItemListPosition *string `json:"item_list_position,omitempty" gtag:"lp,omitempty"`
|
||||
// Example: ChIJIQBpAG2ahYAR_6128GcTUEo
|
||||
LocationID *string `json:"location_id,omitempty" gtag:"lo,omitempty"`
|
||||
// The name of the promotional creative.
|
||||
// Example: summer_banner2
|
||||
CreativeName *string `json:"creative_name,omitempty" gtag:"cn,omitempty"`
|
||||
// The name of the promotional creative slot associated with the item.
|
||||
// Example: featured_app_1
|
||||
CreativeSlot *string `json:"creative_slot,omitempty" gtag:"cs,omitempty"`
|
||||
// Example: 123.45
|
||||
Price *string `json:"price,omitempty" gtag:"pr,omitempty"`
|
||||
// The ID of the promotion associated with the item.
|
||||
// Example: P_12345
|
||||
PromotionID *string `json:"promotion_id,omitempty" gtag:"pi,omitempty"`
|
||||
// The name of the promotion associated with the item.
|
||||
// Example: Summer Sale
|
||||
PromotionName *string `json:"promotion_name,omitempty" gtag:"pn,omitempty"`
|
||||
// Example: 1
|
||||
Quantity *string `json:"quantity,omitempty" gtag:"qt,omitempty"`
|
||||
}
|
||||
90
encoding/gtagencode/mpv2.go
Normal file
90
encoding/gtagencode/mpv2.go
Normal file
@ -0,0 +1,90 @@
|
||||
package gtagencode
|
||||
|
||||
import (
|
||||
"maps"
|
||||
|
||||
"github.com/foomo/sesamy-go/encoding/gtag"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func MPv2[P any](source gtag.Payload, target *mpv2.Payload[P]) error {
|
||||
var sourceData map[string]any
|
||||
// encode gtag event to map
|
||||
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Result: &sourceData,
|
||||
TagName: "json",
|
||||
IgnoreUntaggedFields: true,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create event decoder")
|
||||
}
|
||||
|
||||
if err := dec.Decode(source); err != nil {
|
||||
return errors.Wrap(err, "failed to decode event")
|
||||
}
|
||||
|
||||
// transorm map to match mpv2 format
|
||||
targetData := map[string]any{
|
||||
"client_id": source.ClientID,
|
||||
"user_id": source.UserID,
|
||||
"non_personalized_ads": source.NonPersonalizedAds,
|
||||
"timestamp_micros": source.SST.TFT,
|
||||
}
|
||||
if source.SST != nil && source.SST.TFT != nil {
|
||||
targetData["timestamp_micros"] = gtag.Get(source.SST.TFT) + "000"
|
||||
}
|
||||
|
||||
// combine user properties
|
||||
targetUserProperties := map[string]any{}
|
||||
if node, ok := sourceData["user_property"].(map[string]string); ok {
|
||||
for s, s2 := range node {
|
||||
targetUserProperties[s] = s2
|
||||
}
|
||||
}
|
||||
if node, ok := sourceData["user_property_number"].(map[string]string); ok {
|
||||
for s, s2 := range node {
|
||||
targetUserProperties[s] = s2
|
||||
}
|
||||
}
|
||||
targetData["user_properties"] = targetUserProperties
|
||||
|
||||
// transform event
|
||||
targetEventData := map[string]any{
|
||||
"name": source.EventName,
|
||||
}
|
||||
targetEventDataParams := map[string]any{}
|
||||
if node, ok := sourceData["ecommerce"].(map[string]any); ok {
|
||||
maps.Copy(targetEventDataParams, node)
|
||||
}
|
||||
if node, ok := sourceData["event_parameter"].(map[string]string); ok {
|
||||
for s, s2 := range node {
|
||||
targetEventDataParams[s] = s2
|
||||
}
|
||||
}
|
||||
if node, ok := sourceData["event_parameter_number"].(map[string]string); ok {
|
||||
for s, s2 := range node {
|
||||
targetEventDataParams[s] = s2
|
||||
}
|
||||
}
|
||||
targetEventData["params"] = targetEventDataParams
|
||||
targetData["events"] = []any{targetEventData}
|
||||
|
||||
// encode map to target entity
|
||||
enc, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Result: target,
|
||||
TagName: "json",
|
||||
WeaklyTypedInput: true,
|
||||
IgnoreUntaggedFields: true,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create event encoder")
|
||||
}
|
||||
|
||||
if err := enc.Decode(targetData); err != nil {
|
||||
return errors.Wrap(err, "failed to encode event")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
12
encoding/mpv2/event/addpaymentinfo.go
Normal file
12
encoding/mpv2/event/addpaymentinfo.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type AddPaymentInfo sesamy.Event[params.AddPaymentInfo[params.Item]]
|
||||
|
||||
func NewAddPaymentInfo(p params.AddPaymentInfo[params.Item]) AddPaymentInfo {
|
||||
return AddPaymentInfo(sesamy.NewEvent(sesamy.EventNameAddPaymentInfo, p))
|
||||
}
|
||||
12
encoding/mpv2/event/addshippinginfo.go
Normal file
12
encoding/mpv2/event/addshippinginfo.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type AddShippingInfo sesamy.Event[params.AddShippingInfo[params.Item]]
|
||||
|
||||
func NewAddShippingInfo(p params.AddShippingInfo[params.Item]) AddShippingInfo {
|
||||
return AddShippingInfo(sesamy.NewEvent(sesamy.EventNameAddShippingInfo, p))
|
||||
}
|
||||
12
encoding/mpv2/event/addtocart.go
Normal file
12
encoding/mpv2/event/addtocart.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type AddToCart sesamy.Event[params.AddToCart[params.Item]]
|
||||
|
||||
func NewAddToCart(p params.AddToCart[params.Item]) AddToCart {
|
||||
return AddToCart(sesamy.NewEvent(sesamy.EventNameAddToCart, p))
|
||||
}
|
||||
12
encoding/mpv2/event/addtowishlist.go
Normal file
12
encoding/mpv2/event/addtowishlist.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type AddToWishlist sesamy.Event[params.AddToWishlist[params.Item]]
|
||||
|
||||
func NewAddToWishlist(p params.AddToWishlist[params.Item]) AddToWishlist {
|
||||
return AddToWishlist(sesamy.NewEvent(sesamy.EventNameAddToWishlist, p))
|
||||
}
|
||||
12
encoding/mpv2/event/adimpression.go
Normal file
12
encoding/mpv2/event/adimpression.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type AdImpression sesamy.Event[params.AdImpression]
|
||||
|
||||
func NewAdImpression(p params.AdImpression) AdImpression {
|
||||
return AdImpression(sesamy.NewEvent(sesamy.EventNameAdImpression, p))
|
||||
}
|
||||
12
encoding/mpv2/event/begincheckout.go
Normal file
12
encoding/mpv2/event/begincheckout.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type BeginCheckout sesamy.Event[params.BeginCheckout[params.Item]]
|
||||
|
||||
func NewBeginCheckout(p params.BeginCheckout[params.Item]) BeginCheckout {
|
||||
return BeginCheckout(sesamy.NewEvent(sesamy.EventNameBeginCheckout, p))
|
||||
}
|
||||
12
encoding/mpv2/event/campaigndetails.go
Normal file
12
encoding/mpv2/event/campaigndetails.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type CampaignDetails sesamy.Event[params.CampaignDetails]
|
||||
|
||||
func NewCampaignDetails(p params.CampaignDetails) CampaignDetails {
|
||||
return CampaignDetails(sesamy.NewEvent(sesamy.EventNameCampaignDetails, p))
|
||||
}
|
||||
5
encoding/mpv2/event/doc.go
Normal file
5
encoding/mpv2/event/doc.go
Normal file
@ -0,0 +1,5 @@
|
||||
package event
|
||||
|
||||
// Google Analytics (GA4) Measurement Protocol events
|
||||
//
|
||||
// Reference: https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events
|
||||
12
encoding/mpv2/event/earnvirtualmoney.go
Normal file
12
encoding/mpv2/event/earnvirtualmoney.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type EarnVirtualMoney sesamy.Event[params.EarnVirtualMoney]
|
||||
|
||||
func NewEarnVirtualMoney(p params.EarnVirtualMoney) EarnVirtualMoney {
|
||||
return EarnVirtualMoney(sesamy.NewEvent(sesamy.EventNameEarnVirtualMoney, p))
|
||||
}
|
||||
12
encoding/mpv2/event/generatelead.go
Normal file
12
encoding/mpv2/event/generatelead.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type GenerateLead sesamy.Event[params.GenerateLead]
|
||||
|
||||
func NewGenerateLead(p params.GenerateLead) GenerateLead {
|
||||
return GenerateLead(sesamy.NewEvent(sesamy.EventNameGenerateLead, p))
|
||||
}
|
||||
12
encoding/mpv2/event/joingroup.go
Normal file
12
encoding/mpv2/event/joingroup.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type JoinGroup sesamy.Event[params.JoinGroup]
|
||||
|
||||
func NewJoinGroup(p params.JoinGroup) JoinGroup {
|
||||
return JoinGroup(sesamy.NewEvent(sesamy.EventNameJoinGroup, p))
|
||||
}
|
||||
12
encoding/mpv2/event/levelend.go
Normal file
12
encoding/mpv2/event/levelend.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type LevelEnd sesamy.Event[params.LevelEnd]
|
||||
|
||||
func NewLevelEnd(p params.LevelEnd) LevelEnd {
|
||||
return LevelEnd(sesamy.NewEvent(sesamy.EventNameLevelEnd, p))
|
||||
}
|
||||
12
encoding/mpv2/event/levelstart.go
Normal file
12
encoding/mpv2/event/levelstart.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type LevelStart sesamy.Event[params.LevelStart]
|
||||
|
||||
func NewLevelStart(p params.LevelStart) LevelStart {
|
||||
return LevelStart(sesamy.NewEvent(sesamy.EventNameLevelStart, p))
|
||||
}
|
||||
12
encoding/mpv2/event/levelup.go
Normal file
12
encoding/mpv2/event/levelup.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type LevelUp sesamy.Event[params.LevelUp]
|
||||
|
||||
func NewLevelUp(p params.LevelUp) LevelUp {
|
||||
return LevelUp(sesamy.NewEvent(sesamy.EventNameLevelUp, p))
|
||||
}
|
||||
12
encoding/mpv2/event/login.go
Normal file
12
encoding/mpv2/event/login.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type Login sesamy.Event[params.Login]
|
||||
|
||||
func NewLogin(p params.Login) Login {
|
||||
return Login(sesamy.NewEvent(sesamy.EventNameLogin, p))
|
||||
}
|
||||
12
encoding/mpv2/event/pageview.go
Normal file
12
encoding/mpv2/event/pageview.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type PageView sesamy.Event[params.PageView]
|
||||
|
||||
func NewPageView(p params.PageView) PageView {
|
||||
return PageView(sesamy.NewEvent(sesamy.EventNamePageView, p))
|
||||
}
|
||||
12
encoding/mpv2/event/postscrore.go
Normal file
12
encoding/mpv2/event/postscrore.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type PostScore sesamy.Event[params.PostScore]
|
||||
|
||||
func NewPostScore(p params.PostScore) PostScore {
|
||||
return PostScore(sesamy.NewEvent(sesamy.EventNamePostScore, p))
|
||||
}
|
||||
12
encoding/mpv2/event/purchase.go
Normal file
12
encoding/mpv2/event/purchase.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type Purchase sesamy.Event[params.Purchase[params.Item]]
|
||||
|
||||
func NewPurchase(p params.Purchase[params.Item]) Purchase {
|
||||
return Purchase(sesamy.NewEvent(sesamy.EventNamePurchase, p))
|
||||
}
|
||||
12
encoding/mpv2/event/refund.go
Normal file
12
encoding/mpv2/event/refund.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type Refund sesamy.Event[params.Refund[params.Item]]
|
||||
|
||||
func NewRefund(p params.Refund[params.Item]) Refund {
|
||||
return Refund(sesamy.NewEvent(sesamy.EventNameRefund, p))
|
||||
}
|
||||
12
encoding/mpv2/event/removefromcart.go
Normal file
12
encoding/mpv2/event/removefromcart.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type RemoveFromCart sesamy.Event[params.RemoveFromCart[params.Item]]
|
||||
|
||||
func NewRemoveFromCart(p params.RemoveFromCart[params.Item]) RemoveFromCart {
|
||||
return RemoveFromCart(sesamy.NewEvent(sesamy.EventNameRemoveFromCart, p))
|
||||
}
|
||||
12
encoding/mpv2/event/screenview.go
Normal file
12
encoding/mpv2/event/screenview.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ScreenView sesamy.Event[params.ScreenView]
|
||||
|
||||
func NewScreenView(p params.ScreenView) ScreenView {
|
||||
return ScreenView(sesamy.NewEvent(sesamy.EventNameScreenView, p))
|
||||
}
|
||||
12
encoding/mpv2/event/search.go
Normal file
12
encoding/mpv2/event/search.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type Search sesamy.Event[params.Search]
|
||||
|
||||
func NewSearch(p params.Search) Search {
|
||||
return Search(sesamy.NewEvent(sesamy.EventNameSearch, p))
|
||||
}
|
||||
12
encoding/mpv2/event/selectcontent.go
Normal file
12
encoding/mpv2/event/selectcontent.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type SelectContent sesamy.Event[params.SelectContent]
|
||||
|
||||
func NewSelectContent(p params.SelectContent) SelectContent {
|
||||
return SelectContent(sesamy.NewEvent(sesamy.EventNameSelectContent, p))
|
||||
}
|
||||
12
encoding/mpv2/event/selectitem.go
Normal file
12
encoding/mpv2/event/selectitem.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type SelectItem sesamy.Event[params.SelectItem[params.Item]]
|
||||
|
||||
func NewSelectItem(p params.SelectItem[params.Item]) SelectItem {
|
||||
return SelectItem(sesamy.NewEvent(sesamy.EventNameSelectItem, p))
|
||||
}
|
||||
12
encoding/mpv2/event/selectitempromotion.go
Normal file
12
encoding/mpv2/event/selectitempromotion.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type SelectPromotion sesamy.Event[params.SelectPromotion[params.Item]]
|
||||
|
||||
func NewSelectPromotion(p params.SelectPromotion[params.Item]) SelectPromotion {
|
||||
return SelectPromotion(sesamy.NewEvent(sesamy.EventNameSelectPromotion, p))
|
||||
}
|
||||
12
encoding/mpv2/event/share.go
Normal file
12
encoding/mpv2/event/share.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type Share sesamy.Event[params.Share]
|
||||
|
||||
func NewShare(p params.Share) Share {
|
||||
return Share(sesamy.NewEvent(sesamy.EventNameShare, p))
|
||||
}
|
||||
12
encoding/mpv2/event/signup.go
Normal file
12
encoding/mpv2/event/signup.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type SignUp sesamy.Event[params.SignUp]
|
||||
|
||||
func NewSignUp(p params.SignUp) SignUp {
|
||||
return SignUp(sesamy.NewEvent(sesamy.EventNameSignUp, p))
|
||||
}
|
||||
12
encoding/mpv2/event/spendvirtualmoney.go
Normal file
12
encoding/mpv2/event/spendvirtualmoney.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type SpendVirtualCurrency sesamy.Event[params.SpendVirtualCurrency]
|
||||
|
||||
func NewSpendVirtualCurrency(p params.SpendVirtualCurrency) SpendVirtualCurrency {
|
||||
return SpendVirtualCurrency(sesamy.NewEvent(sesamy.EventNameSpendVirtualCurrency, p))
|
||||
}
|
||||
12
encoding/mpv2/event/tutorialbegin.go
Normal file
12
encoding/mpv2/event/tutorialbegin.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type TutorialBegin sesamy.Event[params.TutorialBegin]
|
||||
|
||||
func NewTutorialBegin(p params.TutorialBegin) TutorialBegin {
|
||||
return TutorialBegin(sesamy.NewEvent(sesamy.EventNameTutorialBegin, p))
|
||||
}
|
||||
12
encoding/mpv2/event/tutorialcomplete.go
Normal file
12
encoding/mpv2/event/tutorialcomplete.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type TutorialComplete sesamy.Event[params.TutorialComplete]
|
||||
|
||||
func NewTutorialComplete(p params.TutorialComplete) TutorialComplete {
|
||||
return TutorialComplete(sesamy.NewEvent(sesamy.EventNameTutorialComplete, p))
|
||||
}
|
||||
12
encoding/mpv2/event/unlockarchievement.go
Normal file
12
encoding/mpv2/event/unlockarchievement.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type UnlockArchievement sesamy.Event[params.UnlockArchievement]
|
||||
|
||||
func NewUnlockArchievement(p params.UnlockArchievement) UnlockArchievement {
|
||||
return UnlockArchievement(sesamy.NewEvent(sesamy.EventNameUnlockArchievement, p))
|
||||
}
|
||||
12
encoding/mpv2/event/viewcart.go
Normal file
12
encoding/mpv2/event/viewcart.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ViewCart sesamy.Event[params.ViewCart[params.Item]]
|
||||
|
||||
func NewViewCart(p params.ViewCart[params.Item]) ViewCart {
|
||||
return ViewCart(sesamy.NewEvent(sesamy.EventNameViewCart, p))
|
||||
}
|
||||
12
encoding/mpv2/event/viewitem.go
Normal file
12
encoding/mpv2/event/viewitem.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ViewItem sesamy.Event[params.ViewItem[params.Item]]
|
||||
|
||||
func NewViewItem(p params.ViewItem[params.Item]) ViewItem {
|
||||
return ViewItem(sesamy.NewEvent(sesamy.EventNameViewItem, p))
|
||||
}
|
||||
12
encoding/mpv2/event/viewitemlist.go
Normal file
12
encoding/mpv2/event/viewitemlist.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ViewItemList sesamy.Event[params.ViewItemList[params.Item]]
|
||||
|
||||
func NewViewItemList(p params.ViewItemList[params.Item]) ViewItemList {
|
||||
return ViewItemList(sesamy.NewEvent(sesamy.EventNameViewItemList, p))
|
||||
}
|
||||
12
encoding/mpv2/event/viewpromotion.go
Normal file
12
encoding/mpv2/event/viewpromotion.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ViewPromotion sesamy.Event[params.ViewPromotion[params.Item]]
|
||||
|
||||
func NewViewPromotion(p params.ViewPromotion[params.Item]) ViewPromotion {
|
||||
return ViewPromotion(sesamy.NewEvent(sesamy.EventNameViewPromotion, p))
|
||||
}
|
||||
12
encoding/mpv2/event/viewsearchresults.go
Normal file
12
encoding/mpv2/event/viewsearchresults.go
Normal file
@ -0,0 +1,12 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/foomo/sesamy-go"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2/params"
|
||||
)
|
||||
|
||||
type ViewSearchResults sesamy.Event[params.ViewSearchResults]
|
||||
|
||||
func NewViewSearchResults(p params.ViewSearchResults) ViewSearchResults {
|
||||
return ViewSearchResults(sesamy.NewEvent(sesamy.EventNameViewSearchResults, p))
|
||||
}
|
||||
8
encoding/mpv2/params/addtocart.go
Normal file
8
encoding/mpv2/params/addtocart.go
Normal file
@ -0,0 +1,8 @@
|
||||
package params
|
||||
|
||||
// AddToCart https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#add_to_cart
|
||||
type AddToCart[Item any] struct {
|
||||
Currency string `json:"currency,omitempty"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
Items []Item `json:"items,omitempty"`
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package params
|
||||
|
||||
// AdImpressionParams https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#ad_impression
|
||||
type AdImpressionParams struct {
|
||||
// AdImpression https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#ad_impression
|
||||
type AdImpression struct {
|
||||
AdPlatform string `json:"ad_platform,omitempty" mapstructure:"ad_platform"`
|
||||
AdSource string `json:"ad_source,omitempty" mapstructure:"ad_source"`
|
||||
AdFormat string `json:"ad_format,omitempty" mapstructure:"ad_format"`
|
||||
@ -1,6 +1,6 @@
|
||||
package params
|
||||
|
||||
type Promotion struct {
|
||||
type Item struct {
|
||||
Affiliation string `json:"affiliation,omitempty"`
|
||||
Coupon string `json:"coupon,omitempty"`
|
||||
CreativeName string `json:"creative_name,omitempty"`
|
||||
8
encoding/mpv2/params/selectitem.go
Normal file
8
encoding/mpv2/params/selectitem.go
Normal file
@ -0,0 +1,8 @@
|
||||
package params
|
||||
|
||||
// SelectItem https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#select_item
|
||||
type SelectItem[Item any] struct {
|
||||
ItemListID string `json:"item_list_id,omitempty" tagging:"item_list_id"`
|
||||
ItemListName string `json:"item_list_name,omitempty" tagging:"item_list_name"`
|
||||
Items []Item `json:"items,omitempty" tagging:"pr"`
|
||||
}
|
||||
@ -6,7 +6,3 @@ type ViewCart[Item any] struct {
|
||||
Value float64 `json:"value,omitempty"`
|
||||
Items []Item `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (e ViewCart[Item]) String() string {
|
||||
return "view_cart"
|
||||
}
|
||||
107
encoding/mpv2encode/gtag.go
Normal file
107
encoding/mpv2encode/gtag.go
Normal file
@ -0,0 +1,107 @@
|
||||
package mpv2encode
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/foomo/sesamy-go/encoding/gtag"
|
||||
"github.com/foomo/sesamy-go/encoding/mpv2"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GTag[P any](source mpv2.Payload[P], target *gtag.Payload) error {
|
||||
targetData := map[string]any{
|
||||
"client_id": source.ClientID,
|
||||
"user_id": source.UserID,
|
||||
"non_personalized_ads": source.NonPersonalizedAds,
|
||||
}
|
||||
|
||||
{ // user_property
|
||||
targetUserProperty := map[string]any{}
|
||||
targetUserPropertyNumber := map[string]any{}
|
||||
for k, v := range source.UserProperties {
|
||||
if s, ok := v.(string); ok {
|
||||
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
||||
targetUserPropertyNumber[k] = f
|
||||
} else {
|
||||
targetUserProperty[k] = v
|
||||
}
|
||||
} else {
|
||||
targetUserProperty[k] = fmt.Sprintf("%s", v)
|
||||
}
|
||||
}
|
||||
targetData["user_property"] = targetUserProperty
|
||||
targetData["user_property_number"] = targetUserPropertyNumber
|
||||
}
|
||||
|
||||
sourceData := map[string]any{}
|
||||
|
||||
out, err := json.Marshal(source.Events[0])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal event")
|
||||
}
|
||||
if err = json.Unmarshal(out, &sourceData); err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshal source events")
|
||||
}
|
||||
|
||||
{ // ecommerce
|
||||
targetData["event_name"] = sourceData["name"]
|
||||
|
||||
if params, ok := sourceData["params"].(map[string]any); ok {
|
||||
targetEcommerceData := map[string]any{
|
||||
"currency": params["currency"],
|
||||
"promotion_id": params["promotion_id"],
|
||||
"promotion_name": params["promotion_name"],
|
||||
"location_id": params["location_id"],
|
||||
"is_conversion": params["is_conversion"],
|
||||
}
|
||||
delete(params, "currency")
|
||||
delete(params, "promotion_id")
|
||||
delete(params, "promotion_name")
|
||||
delete(params, "location_id")
|
||||
delete(params, "is_conversion")
|
||||
|
||||
targetData["ecommerce"] = targetEcommerceData
|
||||
targetData["items"] = params["items"]
|
||||
delete(params, "items")
|
||||
|
||||
{ // user_property
|
||||
targetEventProperty := map[string]any{}
|
||||
targetEventPropertyNumber := map[string]any{}
|
||||
for k, v := range params {
|
||||
if s, ok := v.(string); ok {
|
||||
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
||||
targetEventPropertyNumber[k] = f
|
||||
} else {
|
||||
targetEventProperty[k] = v
|
||||
}
|
||||
} else {
|
||||
targetEventProperty[k] = fmt.Sprintf("%s", v)
|
||||
}
|
||||
}
|
||||
targetData["event_parameter"] = targetEventProperty
|
||||
targetData["event_parameter_number"] = targetEventPropertyNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// encode gtag event to map
|
||||
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
WeaklyTypedInput: true,
|
||||
Squash: true,
|
||||
Result: &target,
|
||||
TagName: "json",
|
||||
IgnoreUntaggedFields: true,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create event decoder")
|
||||
}
|
||||
|
||||
if err := dec.Decode(targetData); err != nil {
|
||||
return errors.Wrap(err, "failed to decode event")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user