Skip to content

Commit

Permalink
Added new conversion rate and custom metric fields, added missing eve…
Browse files Browse the repository at this point in the history
…nt meta, timezone, offset, sort, direction, and search fields in filter, removed screen_width and screen_height from filter.
  • Loading branch information
Kugelschieber committed Sep 16, 2023
1 parent b3d4f98 commit ed55a9e
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 64 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 2.1.0

* added new conversion rate and custom metric fields
* added missing event meta, timezone, offset, sort, direction, and search fields in filter
* removed screen_width and screen_height from filter

## 2.0.0

* added optional client hint headers
Expand Down
16 changes: 16 additions & 0 deletions pkg/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@ func (client *Client) getStatsRequestURL(endpoint string, filter *Filter) string
v.Set("id", filter.DomainID)
v.Set("from", filter.From.Format("2006-01-02"))
v.Set("to", filter.To.Format("2006-01-02"))
v.Set("scale", string(filter.Scale))
v.Set("tz", filter.Timezone)
v.Set("path", filter.Path)
v.Set("entry_path", filter.EntryPath)
v.Set("exit_path", filter.ExitPath)
Expand All @@ -797,7 +799,21 @@ func (client *Client) getStatsRequestURL(endpoint string, filter *Filter) string
v.Set("utm_campaign", filter.UTMCampaign)
v.Set("utm_content", filter.UTMContent)
v.Set("utm_term", filter.UTMTerm)
v.Set("custom_metric_key", filter.CustomMetricKey)
v.Set("custom_metric_type", string(filter.CustomMetricType))
v.Set("offset", strconv.Itoa(filter.Offset))
v.Set("limit", strconv.Itoa(filter.Limit))
v.Set("sort", filter.Sort)
v.Set("direction", filter.Direction)
v.Set("search", filter.Search)

if filter.Start > 0 {
v.Set("start", strconv.Itoa(filter.Start))
}

for key, value := range filter.EventMeta {
v.Set(fmt.Sprintf("meta_%s", key), value)
}

if filter.IncludeAvgTimeOnPage {
v.Set("include_avg_time_on_page", "true")
Expand Down
43 changes: 43 additions & 0 deletions pkg/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http/httptest"
"os"
"testing"
"time"
)

func TestGetReferrerFromHeaderOrQuery(t *testing.T) {
Expand Down Expand Up @@ -40,3 +41,45 @@ func TestNewClient(t *testing.T) {
assert.NotNil(t, d)
}
}

func TestGetStatsRequestURL(t *testing.T) {
client := NewClient("", "", nil)
url := client.getStatsRequestURL("/api/v1/test", &Filter{
DomainID: "o93jnhf",
From: time.Date(2023, 8, 1, 0, 0, 0, 0, time.UTC),
To: time.Date(2023, 8, 20, 0, 0, 0, 0, time.UTC),
Start: 500,
Scale: ScaleDay,
Timezone: "Europe/Berlin",
Path: "/path",
Pattern: "/pattern",
EntryPath: "/entry",
ExitPath: "/exit",
Event: "event",
EventMetaKey: "event_meta_key",
EventMeta: map[string]string{"meta": "value"},
Language: "en",
Country: "us",
City: "New York",
Referrer: "referrer",
ReferrerName: "referrer_name",
OS: "Windows",
Browser: "Firefox",
Platform: "desktop",
ScreenClass: "XXL",
UTMSource: "source",
UTMMedium: "medium",
UTMCampaign: "campaign",
UTMContent: "content",
UTMTerm: "term",
CustomMetricKey: "custom_metric_key",
CustomMetricType: CustomMetricTypeInteger,
IncludeAvgTimeOnPage: true,
Offset: 5,
Limit: 42,
Sort: "sort",
Direction: "asc",
Search: "search",
})
assert.Equal(t, "https://api.pirsch.io/api/v1/test?browser=Firefox&city=New+York&country=us&custom_metric_key=custom_metric_key&custom_metric_type=integer&direction=asc&entry_path=%2Fentry&event=event&event_meta_key=event_meta_key&exit_path=%2Fexit&from=2023-08-01&id=o93jnhf&include_avg_time_on_page=true&language=en&limit=42&meta_meta=value&offset=5&os=Windows&path=%2Fpath&pattern=%2Fpattern&platform=desktop&referrer=referrer&referrer_name=referrer_name&scale=day&screen_class=XXL&search=search&sort=sort&start=500&to=2023-08-20&tz=Europe%2FBerlin&utm_campaign=campaign&utm_content=content&utm_medium=medium&utm_source=source&utm_term=term", url)
}
31 changes: 31 additions & 0 deletions pkg/key_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package pkg

import (
"database/sql/driver"
"encoding/json"
"errors"
)

// KeyValue is a key value map that can be stored as jsonb.
type KeyValue map[string]string

func (kv *KeyValue) Value() (driver.Value, error) {
return json.Marshal(kv)
}

func (kv *KeyValue) Scan(value interface{}) error {
var data []byte

switch v := value.(type) {
case string:
data = []byte(v)
case []byte:
data = v
case nil:
return nil
default:
return errors.New("type assertion failed")
}

return json.Unmarshal(data, &kv)
}
168 changes: 104 additions & 64 deletions pkg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,22 @@ const (

// ScaleYear groups results by year.
ScaleYear = "year"

// CustomMetricTypeInteger sets the custom metric type to integer.
CustomMetricTypeInteger = "integer"

// CustomMetricTypeFloat sets the custom metric type to float.
CustomMetricTypeFloat = "float"
)

// Scale is used to group results in the Filter.
// Use one of the constants ScaleDay, ScaleWeek, ScaleMonth, ScaleYear.
type Scale string

// CustomMetricType is used to set the type for a custom metric in the Filter.
// Use one of the constants CustomMetricTypeInteger or CustomMetricTypeFloat.
type CustomMetricType string

// PageView are the parameters to send a page hit to Pirsch.
type PageView struct {
Hostname string
Expand Down Expand Up @@ -54,35 +64,41 @@ type Event struct {
// Filter is used to filter statistics.
// DomainID, From, and To are required dates (the time is ignored).
type Filter struct {
DomainID string `json:"id"`
From time.Time `json:"from"`
To time.Time `json:"to"`
Start int `json:"start,omitempty"`
Scale Scale `json:"scale,omitempty"`
Path string `json:"path,omitempty"`
Pattern string `json:"pattern,omitempty"`
EntryPath string `json:"entry_path,omitempty"`
ExitPath string `json:"exit_path,omitempty"`
Event string `json:"event,omitempty"`
EventMetaKey string `json:"event_meta_key,omitempty"`
Language string `json:"language,omitempty"`
Country string `json:"country,omitempty"`
City string `json:"city,omitempty"`
Referrer string `json:"referrer,omitempty"`
ReferrerName string `json:"referrer_name,omitempty"`
OS string `json:"os,omitempty"`
Browser string `json:"browser,omitempty"`
Platform string `json:"platform,omitempty"`
ScreenClass string `json:"screen_class,omitempty"`
ScreenWidth string `json:"screen_width,omitempty"`
ScreenHeight string `json:"screen_height,omitempty"`
UTMSource string `json:"utm_source,omitempty"`
UTMMedium string `json:"utm_medium,omitempty"`
UTMCampaign string `json:"utm_campaign,omitempty"`
UTMContent string `json:"utm_content,omitempty"`
UTMTerm string `json:"utm_term,omitempty"`
Limit int `json:"limit,omitempty"`
IncludeAvgTimeOnPage bool `json:"include_avg_time_on_page,omitempty"`
DomainID string `json:"id"`
From time.Time `json:"from"`
To time.Time `json:"to"`
Start int `json:"start,omitempty"`
Scale Scale `json:"scale,omitempty"`
Timezone string `json:"tz,omitempty"`
Path string `json:"path,omitempty"`
Pattern string `json:"pattern,omitempty"`
EntryPath string `json:"entry_path,omitempty"`
ExitPath string `json:"exit_path,omitempty"`
Event string `json:"event,omitempty"`
EventMetaKey string `json:"event_meta_key,omitempty"`
EventMeta map[string]string `json:"-"`
Language string `json:"language,omitempty"`
Country string `json:"country,omitempty"`
City string `json:"city,omitempty"`
Referrer string `json:"referrer,omitempty"`
ReferrerName string `json:"referrer_name,omitempty"`
OS string `json:"os,omitempty"`
Browser string `json:"browser,omitempty"`
Platform string `json:"platform,omitempty"`
ScreenClass string `json:"screen_class,omitempty"`
UTMSource string `json:"utm_source,omitempty"`
UTMMedium string `json:"utm_medium,omitempty"`
UTMCampaign string `json:"utm_campaign,omitempty"`
UTMContent string `json:"utm_content,omitempty"`
UTMTerm string `json:"utm_term,omitempty"`
CustomMetricKey string `json:"custom_metric_key,omitempty"`
CustomMetricType CustomMetricType `json:"custom_metric_type,omitempty"`
IncludeAvgTimeOnPage bool `json:"include_avg_time_on_page,omitempty"`
Offset int `json:"offset,omitempty"`
Limit int `json:"limit,omitempty"`
Sort string `json:"sort,omitempty"`
Direction string `json:"direction,omitempty"`
Search string `json:"search,omitempty"`
}

// BaseEntity contains the base data for all entities.
Expand All @@ -96,16 +112,28 @@ type BaseEntity struct {
type Domain struct {
BaseEntity

UserID string `json:"user_id"`
Hostname string `json:"hostname"`
Subdomain string `json:"subdomain"`
IdentificationCode string `json:"identification_code"`
Public bool `json:"public"`
GoogleUserID null.String `json:"google_user_id"`
GoogleUserEmail null.String `json:"google_user_email"`
GSCDomain null.String `json:"gsc_domain"`
NewOwner null.Int64 `json:"new_owner"`
Timezone null.String `json:"timezone"`
UserID string `json:"user_id"`
OrganizationID string `json:"organization_id"`
Hostname string `json:"hostname"`
Subdomain string `json:"subdomain"`
IdentificationCode string `json:"identification_code"`
Public bool `json:"public"`
GoogleUserID null.String `json:"google_user_id"`
GoogleUserEmail null.String `json:"google_user_email"`
GSCDomain null.String `json:"gsc_domain"`
NewOwner null.Int64 `json:"new_owner"`
Timezone null.String `json:"timezone"`
GroupByTitle bool `json:"group_by_title"`
ActiveVisitorsSeconds null.Int64 `json:"active_visitors_seconds"`
DisableScripts bool `json:"disable_scripts"`
StatisticsStart null.Time `json:"statistics_start"`
ImportedStatistics bool `json:"imported_statistics"`
ThemeID string `json:"theme_id"`
Theme KeyValue `json:"theme"`
CustomDomain null.String `json:"custom_domain"`
UserRole string `json:"user_role"`
Settings KeyValue `json:"settings"`
ThemeSettings KeyValue `json:"theme_settings"`
}

// TimeSpentStats is the time spent on the website or specific pages.
Expand Down Expand Up @@ -157,24 +185,30 @@ type UTMTermStats struct {

// TotalVisitorStats is the result type for total visitor statistics.
type TotalVisitorStats struct {
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
CR float64 `json:"cr"`
CustomMetricAvg float64 `json:"custom_metric_avg"`
CustomMetricTotal float64 `json:"custom_metric_total"`
}

// VisitorStats is the result type for visitor statistics.
type VisitorStats struct {
Day null.Time `json:"day"`
Week null.Time `json:"week"`
Month null.Time `json:"month"`
Year null.Time `json:"year"`
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
Day null.Time `json:"day"`
Week null.Time `json:"week"`
Month null.Time `json:"month"`
Year null.Time `json:"year"`
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
CR float64 `json:"cr"`
CustomMetricAvg float64 `json:"custom_metric_avg"`
CustomMetricTotal float64 `json:"custom_metric_total"`
}

// PageStats is the result type for page statistics.
Expand Down Expand Up @@ -266,11 +300,14 @@ type ConversionGoalStats struct {

// Growth represents the visitors, views, sessions, bounces, and average session duration growth between two time periods.
type Growth struct {
VisitorsGrowth float64 `json:"visitors_growth"`
ViewsGrowth float64 `json:"views_growth"`
SessionsGrowth float64 `json:"sessions_growth"`
BouncesGrowth float64 `json:"bounces_growth"`
TimeSpentGrowth float64 `json:"time_spent_growth"`
VisitorsGrowth float64 `json:"visitors_growth"`
ViewsGrowth float64 `json:"views_growth"`
SessionsGrowth float64 `json:"sessions_growth"`
BouncesGrowth float64 `json:"bounces_growth"`
TimeSpentGrowth float64 `json:"time_spent_growth"`
CRGrowth float64 `json:"cr_growth"`
CustomMetricAvgGrowth float64 `json:"custom_metric_avg_growth"`
CustomMetricTotalGrowth float64 `json:"custom_metric_total_growth"`
}

// ActiveVisitorStats is the result type for active visitor statistics.
Expand All @@ -288,12 +325,15 @@ type ActiveVisitorsData struct {

// VisitorHourStats is the result type for visitor statistics grouped by time of day.
type VisitorHourStats struct {
Hour int `json:"hour"`
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
Hour int `json:"hour"`
Visitors int `json:"visitors"`
Views int `json:"views"`
Sessions int `json:"sessions"`
Bounces int `json:"bounces"`
BounceRate float64 `json:"bounce_rate"`
CR float64 `json:"cr"`
CustomMetricAvg float64 `json:"custom_metric_avg"`
CustomMetricTotal float64 `json:"custom_metric_total"`
}

// LanguageStats is the result type for language statistics.
Expand Down

0 comments on commit ed55a9e

Please sign in to comment.