diff --git a/.changelog/1474.txt b/.changelog/1474.txt new file mode 100644 index 00000000000..6c275e3ec45 --- /dev/null +++ b/.changelog/1474.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +zaraz: Add support for CRUD APIs +``` diff --git a/zaraz.go b/zaraz.go new file mode 100644 index 00000000000..dedfdc4c977 --- /dev/null +++ b/zaraz.go @@ -0,0 +1,421 @@ +package cloudflare + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/goccy/go-json" +) + +type ZarazConfig struct { + DebugKey string `json:"debugKey"` + Tools map[string]ZarazTool `json:"tools"` + Triggers map[string]ZarazTrigger `json:"triggers"` + ZarazVersion int64 `json:"zarazVersion"` + Consent ZarazConsent `json:"consent,omitempty"` + DataLayer *bool `json:"dataLayer,omitempty"` + Dlp []any `json:"dlp,omitempty"` + HistoryChange *bool `json:"historyChange,omitempty"` + Settings ZarazConfigSettings `json:"settings,omitempty"` + Variables map[string]ZarazVariable `json:"variables,omitempty"` +} + +type ZarazWorker struct { + EscapedWorkerName string `json:"escapedWorkerName"` + WorkerTag string `json:"workerTag"` + MutableId string `json:"mutableId,omitempty"` +} +type ZarazConfigSettings struct { + AutoInjectScript *bool `json:"autoInjectScript"` + InjectIframes *bool `json:"injectIframes,omitempty"` + Ecommerce *bool `json:"ecommerce,omitempty"` + HideQueryParams *bool `json:"hideQueryParams,omitempty"` + HideIpAddress *bool `json:"hideIPAddress,omitempty"` + HideUserAgent *bool `json:"hideUserAgent,omitempty"` + HideExternalReferer *bool `json:"hideExternalReferer,omitempty"` + CookieDomain string `json:"cookieDomain,omitempty"` + InitPath string `json:"initPath,omitempty"` + ScriptPath string `json:"scriptPath,omitempty"` + TrackPath string `json:"trackPath,omitempty"` + EventsApiPath string `json:"eventsApiPath,omitempty"` + McRootPath string `json:"mcRootPath,omitempty"` + ContextEnricher ZarazWorker `json:"contextEnricher,omitempty"` +} + +type ZarazNeoEvent struct { + BlockingTriggers []string `json:"blockingTriggers"` + FiringTriggers []string `json:"firingTriggers"` + Data map[string]any `json:"data"` + ActionType string `json:"actionType,omitempty"` +} + +type ZarazToolType string + +const ( + ZarazToolLibrary ZarazToolType = "library" + ZarazToolComponent ZarazToolType = "component" + ZarazToolCustomMc ZarazToolType = "custom-mc" +) + +type ZarazTool struct { + BlockingTriggers []string `json:"blockingTriggers"` + Enabled *bool `json:"enabled"` + DefaultFields map[string]any `json:"defaultFields"` + Name string `json:"name"` + NeoEvents []ZarazNeoEvent `json:"neoEvents"` + Type ZarazToolType `json:"type"` + DefaultPurpose string `json:"defaultPurpose,omitempty"` + Library string `json:"library,omitempty"` + Component string `json:"component,omitempty"` + Permissions []string `json:"permissions,omitempty"` + Settings map[string]any `json:"settings,omitempty"` + Worker ZarazWorker `json:"worker,omitempty"` +} + +type ZarazTriggerSystem string + +const ZarazPageload ZarazTriggerSystem = "pageload" + +type ZarazLoadRuleOp string + +type ZarazRuleType string + +const ( + ZarazClickListener ZarazRuleType = "clickListener" + ZarazTimer ZarazRuleType = "timer" + ZarazFormSubmission ZarazRuleType = "formSubmission" + ZarazVariableMatch ZarazRuleType = "variableMatch" + ZarazScrollDepth ZarazRuleType = "scrollDepth" + ZarazElementVisibility ZarazRuleType = "elementVisibility" + ZarazClientEval ZarazRuleType = "clientEval" +) + +type ZarazSelectorType string + +const ( + ZarazXPath ZarazSelectorType = "xpath" + ZarazCSS ZarazSelectorType = "css" +) + +type ZarazRuleSettings struct { + Type ZarazSelectorType `json:"type,omitempty"` + Selector string `json:"selector,omitempty"` + WaitForTags int `json:"waitForTags,omitempty"` + Interval int `json:"interval,omitempty"` + Limit int `json:"limit,omitempty"` + Validate *bool `json:"validate,omitempty"` + Variable string `json:"variable,omitempty"` + Match string `json:"match,omitempty"` + Positions string `json:"positions,omitempty"` + Op ZarazLoadRuleOp `json:"op,omitempty"` + Value string `json:"value,omitempty"` +} + +type ZarazTriggerRule struct { + Id string `json:"id"` + Match string `json:"match,omitempty"` + Op ZarazLoadRuleOp `json:"op,omitempty"` + Value string `json:"value,omitempty"` + Action ZarazRuleType `json:"action"` + Settings ZarazRuleSettings `json:"settings"` +} + +type ZarazTrigger struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + LoadRules []ZarazTriggerRule `json:"loadRules"` + ExcludeRules []ZarazTriggerRule `json:"excludeRules"` + ClientRules []any `json:"clientRules,omitempty"` // what is this? + System ZarazTriggerSystem `json:"system,omitempty"` +} + +type ZarazVariableType string + +const ( + ZarazVarString ZarazVariableType = "string" + ZarazVarSecret ZarazVariableType = "secret" + ZarazVarWorker ZarazVariableType = "worker" +) + +type ZarazVariable struct { + Name string `json:"name"` + Type ZarazVariableType `json:"type"` + Value interface{} `json:"value"` +} + +type ZarazButtonTextTranslations struct { + AcceptAll map[string]string `json:"accept_all"` + RejectAll map[string]string `json:"reject_all"` + ConfirmMyChoices map[string]string `json:"confirm_my_choices"` +} + +type ZarazPurpose struct { + Name string `json:"name"` + Description string `json:"description"` +} + +type ZarazPurposeWithTranslations struct { + Name map[string]string `json:"name"` + Description map[string]string `json:"description"` + Order int `json:"order"` +} + +type ZarazConsent struct { + Enabled *bool `json:"enabled"` + ButtonTextTranslations ZarazButtonTextTranslations `json:"buttonTextTranslations,omitempty"` + CompanyEmail string `json:"companyEmail,omitempty"` + CompanyName string `json:"companyName,omitempty"` + CompanyStreetAddress string `json:"companyStreetAddress,omitempty"` + ConsentModalIntroHTML string `json:"consentModalIntroHTML,omitempty"` + ConsentModalIntroHTMLWithTranslations map[string]string `json:"consentModalIntroHTMLWithTranslations,omitempty"` + CookieName string `json:"cookieName,omitempty"` + CustomCSS string `json:"customCSS,omitempty"` + CustomIntroDisclaimerDismissed *bool `json:"customIntroDisclaimerDismissed,omitempty"` + DefaultLanguage string `json:"defaultLanguage,omitempty"` + HideModal *bool `json:"hideModal,omitempty"` + Purposes map[string]ZarazPurpose `json:"purposes,omitempty"` + PurposesWithTranslations map[string]ZarazPurposeWithTranslations `json:"purposesWithTranslations,omitempty"` +} + +type ZarazConfigResponse struct { + Result ZarazConfig `json:"result"` + Response +} + +type ZarazWorkflowResponse struct { + Result string `json:"result"` + Response +} + +type ZarazPublishResponse struct { + Result string `json:"result"` + Response +} + +type UpdateZarazConfigParams struct { + DebugKey string `json:"debugKey"` + Tools map[string]ZarazTool `json:"tools"` + Triggers map[string]ZarazTrigger `json:"triggers"` + ZarazVersion int64 `json:"zarazVersion"` + Consent ZarazConsent `json:"consent,omitempty"` + DataLayer *bool `json:"dataLayer,omitempty"` + Dlp []any `json:"dlp,omitempty"` + HistoryChange *bool `json:"historyChange,omitempty"` + Settings ZarazConfigSettings `json:"settings,omitempty"` + Variables map[string]ZarazVariable `json:"variables,omitempty"` +} + +type UpdateZarazWorkflowParams struct { + Workflow string `json:"workflow"` +} + +type PublishZarazConfigParams struct { + Description string `json:"description"` +} + +type ZarazHistoryRecord struct { + ID int64 `json:"id,omitempty"` + UserID string `json:"userId,omitempty"` + Description string `json:"description,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` +} + +type ZarazConfigHistoryListResponse struct { + Result []ZarazHistoryRecord `json:"result"` + Response + ResultInfo `json:"result_info"` +} + +type ListZarazConfigHistoryParams struct { + ResultInfo +} + +type GetZarazConfigsByIdResponse = map[string]interface{} + +// listZarazConfigHistoryDefaultPageSize represents the default per_page size of the API. +var listZarazConfigHistoryDefaultPageSize int = 100 + +func (api *API) GetZarazConfig(ctx context.Context, rc *ResourceContainer) (ZarazConfigResponse, error) { + if rc.Identifier == "" { + return ZarazConfigResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/config", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return ZarazConfigResponse{}, err + } + + var recordResp ZarazConfigResponse + err = json.Unmarshal(res, &recordResp) + if err != nil { + return ZarazConfigResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return recordResp, nil +} + +func (api *API) UpdateZarazConfig(ctx context.Context, rc *ResourceContainer, params UpdateZarazConfigParams) (ZarazConfigResponse, error) { + if rc.Identifier == "" { + return ZarazConfigResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/config", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) + if err != nil { + return ZarazConfigResponse{}, err + } + + var updateResp ZarazConfigResponse + err = json.Unmarshal(res, &updateResp) + if err != nil { + return ZarazConfigResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return updateResp, nil +} + +func (api *API) GetZarazWorkflow(ctx context.Context, rc *ResourceContainer) (ZarazWorkflowResponse, error) { + if rc.Identifier == "" { + return ZarazWorkflowResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/workflow", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return ZarazWorkflowResponse{}, err + } + + var response ZarazWorkflowResponse + err = json.Unmarshal(res, &response) + if err != nil { + return ZarazWorkflowResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return response, nil +} + +func (api *API) UpdateZarazWorkflow(ctx context.Context, rc *ResourceContainer, params UpdateZarazWorkflowParams) (ZarazWorkflowResponse, error) { + if rc.Identifier == "" { + return ZarazWorkflowResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/workflow", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params.Workflow) + if err != nil { + return ZarazWorkflowResponse{}, err + } + + var response ZarazWorkflowResponse + err = json.Unmarshal(res, &response) + if err != nil { + return ZarazWorkflowResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return response, nil +} + +func (api *API) PublishZarazConfig(ctx context.Context, rc *ResourceContainer, params PublishZarazConfigParams) (ZarazPublishResponse, error) { + if rc.Identifier == "" { + return ZarazPublishResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/publish", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params.Description) + if err != nil { + return ZarazPublishResponse{}, err + } + + var response ZarazPublishResponse + err = json.Unmarshal(res, &response) + if err != nil { + return ZarazPublishResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return response, nil +} + +func (api *API) ListZarazConfigHistory(ctx context.Context, rc *ResourceContainer, params ListZarazConfigHistoryParams) ([]ZarazHistoryRecord, *ResultInfo, error) { + if rc.Identifier == "" { + return nil, nil, ErrMissingZoneID + } + + autoPaginate := true + if params.PerPage >= 1 || params.Page >= 1 { + autoPaginate = false + } + + if params.PerPage < 1 { + params.PerPage = listZarazConfigHistoryDefaultPageSize + } + + if params.Page < 1 { + params.Page = 1 + } + + var records []ZarazHistoryRecord + var lastResultInfo ResultInfo + + for { + uri := buildURI(fmt.Sprintf("/zones/%s/settings/zaraz/v2/history", rc.Identifier), params) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []ZarazHistoryRecord{}, &ResultInfo{}, err + } + var listResponse ZarazConfigHistoryListResponse + err = json.Unmarshal(res, &listResponse) + if err != nil { + return []ZarazHistoryRecord{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + records = append(records, listResponse.Result...) + lastResultInfo = listResponse.ResultInfo + params.ResultInfo = listResponse.ResultInfo.Next() + if params.ResultInfo.Done() || !autoPaginate { + break + } + } + return records, &lastResultInfo, nil +} + +func (api *API) GetDefaultZarazConfig(ctx context.Context, rc *ResourceContainer) (ZarazConfigResponse, error) { + if rc.Identifier == "" { + return ZarazConfigResponse{}, ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/default", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return ZarazConfigResponse{}, err + } + + var recordResp ZarazConfigResponse + err = json.Unmarshal(res, &recordResp) + if err != nil { + return ZarazConfigResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return recordResp, nil +} + +func (api *API) ExportZarazConfig(ctx context.Context, rc *ResourceContainer) error { + if rc.Identifier == "" { + return ErrMissingZoneID + } + + uri := fmt.Sprintf("/zones/%s/settings/zaraz/v2/export", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return err + } + + var recordResp ZarazConfig + err = json.Unmarshal(res, &recordResp) + if err != nil { + return fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return nil +} diff --git a/zaraz_test.go b/zaraz_test.go new file mode 100644 index 00000000000..a59115e3efb --- /dev/null +++ b/zaraz_test.go @@ -0,0 +1,741 @@ +package cloudflare + +import ( + "context" + "fmt" + "io" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var trueValue bool = true +var falseValue bool = false + +var expectedConfig ZarazConfig = ZarazConfig{ + DebugKey: "cheese", + ZarazVersion: 44, + DataLayer: &trueValue, + Dlp: []any{}, + HistoryChange: &trueValue, + Settings: ZarazConfigSettings{ + AutoInjectScript: &trueValue, + }, + Tools: map[string]ZarazTool{ + "PBQr": { + BlockingTriggers: []string{}, + Enabled: &trueValue, + DefaultFields: map[string]any{}, + Name: "Custom HTML", + NeoEvents: []ZarazNeoEvent{ + { + ActionType: "event", + BlockingTriggers: []string{}, + Data: map[string]any{ + "__zaraz_setting_name": "pageview1", + "htmlCode": "", + }, + FiringTriggers: []string{"Pageview"}, + }, + }, + Type: ZarazToolComponent, + DefaultPurpose: "rJJC", + Component: "html", + Permissions: []string{"execute_unsafe_scripts"}, + Settings: map[string]any{}, + }, + }, + Triggers: map[string]ZarazTrigger{ + "Pageview": { + Name: "Pageview", + Description: "All page loads", + LoadRules: []ZarazTriggerRule{{Match: "{{ client.__zarazTrack }}", Op: "EQUALS", Value: "Pageview"}}, + ExcludeRules: []ZarazTriggerRule{}, + ClientRules: []any{}, + System: ZarazPageload, + }, + "TFOl": { + Name: "test", + Description: "", + LoadRules: []ZarazTriggerRule{{Id: "Kqsc", Match: "test", Op: "CONTAINS", Value: "test"}, {Id: "EDnV", Action: ZarazClickListener, Settings: ZarazRuleSettings{Selector: "test", Type: ZarazCSS}}}, + ExcludeRules: []ZarazTriggerRule{}, + }, + }, + Variables: map[string]ZarazVariable{ + "jwIx": { + Name: "test", + Type: ZarazVarString, + Value: "sss", + }, + "pAuL": { + Name: "test-worker-var", + Type: ZarazVarWorker, + Value: map[string]interface{}{ + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf", + }, + }, + }, + Consent: ZarazConsent{ + Enabled: &trueValue, + ButtonTextTranslations: ZarazButtonTextTranslations{ + AcceptAll: map[string]string{"en": "Accept ALL"}, + ConfirmMyChoices: map[string]string{"en": "YES!"}, + RejectAll: map[string]string{"en": "Reject ALL"}, + }, + CompanyEmail: "email@example.com", + ConsentModalIntroHTMLWithTranslations: map[string]string{"en": "Lorem ipsum dolar set Amet?"}, + CookieName: "zaraz-consent", + CustomCSS: ".test {\n color: red;\n}", + CustomIntroDisclaimerDismissed: &trueValue, + DefaultLanguage: "en", + HideModal: &falseValue, + PurposesWithTranslations: map[string]ZarazPurposeWithTranslations{ + "rJJC": { + Description: map[string]string{"en": "Blah blah"}, + Name: map[string]string{"en": "Analytics"}, + Order: 0, + }, + }, + }, +} + +func TestGetZarazConfig(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + + w.Header().Set("content-type", "application/json") + + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": { + "consent": { + "buttonTextTranslations": { + "accept_all": { + "en": "Accept ALL" + }, + "confirm_my_choices": { + "en": "YES!" + }, + "reject_all": { + "en": "Reject ALL" + } + }, + "companyEmail": "email@example.com", + "consentModalIntroHTMLWithTranslations": { + "en": "Lorem ipsum dolar set Amet?" + }, + "cookieName": "zaraz-consent", + "customCSS": ".test {\n color: red;\n}", + "customIntroDisclaimerDismissed": true, + "defaultLanguage": "en", + "enabled": true, + "hideModal": false, + "purposesWithTranslations": { + "rJJC": { + "description": { + "en": "Blah blah" + }, + "name": { + "en": "Analytics" + }, + "order": 0 + } + } + }, + "dataLayer": true, + "debugKey": "cheese", + "dlp": [], + "historyChange": true, + "invalidKey": "cheese", + "settings": { + "autoInjectScript": true + }, + "tools": { + "PBQr": { + "blockingTriggers": [], + "component": "html", + "defaultFields": {}, + "defaultPurpose": "rJJC", + "enabled": true, + "mode": { + "cloud": false, + "ignoreSPA": true, + "light": false, + "sample": false, + "segment": { + "end": 100, + "start": 0 + }, + "trigger": "pageload" + }, + "name": "Custom HTML", + "neoEvents": [ + { + "actionType": "event", + "blockingTriggers": [], + "data": { + "__zaraz_setting_name": "pageview1", + "htmlCode": "" + }, + "firingTriggers": [ + "Pageview" + ] + } + ], + "permissions": [ + "execute_unsafe_scripts" + ], + "settings": {}, + "type": "component" + } + }, + "triggers": { + "Pageview": { + "clientRules": [], + "description": "All page loads", + "excludeRules": [], + "loadRules": [ + { + "match": "{{ client.__zarazTrack }}", + "op": "EQUALS", + "value": "Pageview" + } + ], + "name": "Pageview", + "system": "pageload" + }, + "TFOl": { + "description": "", + "excludeRules": [], + "loadRules": [ + { + "id": "Kqsc", + "match": "test", + "op": "CONTAINS", + "value": "test" + }, + { + "action": "clickListener", + "id": "EDnV", + "settings": { + "selector": "test", + "type": "css", + "waitForTags": 0 + } + } + ], + "name": "test" + } + }, + "variables": { + "jwIx": { + "name": "test", + "type": "string", + "value": "sss" + }, + "pAuL": { + "name": "test-worker-var", + "type": "worker", + "value": { + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf" + } + } + }, + "zarazVersion": 44 + } + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/config", handler) + + actual, err := client.GetZarazConfig(context.Background(), ZoneIdentifier(testZoneID)) + require.NoError(t, err) + + assert.Equal(t, expectedConfig, actual.Result) +} + +func TestUpdateZarazConfig(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) + + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": { + "consent": { + "buttonTextTranslations": { + "accept_all": { + "en": "Accept ALL" + }, + "confirm_my_choices": { + "en": "YES!" + }, + "reject_all": { + "en": "Reject ALL" + } + }, + "companyEmail": "email@example.com", + "consentModalIntroHTMLWithTranslations": { + "en": "Lorem ipsum dolar set Amet?" + }, + "cookieName": "zaraz-consent", + "customCSS": ".test {\n color: red;\n}", + "customIntroDisclaimerDismissed": true, + "defaultLanguage": "en", + "enabled": true, + "hideModal": false, + "purposesWithTranslations": { + "rJJC": { + "description": { + "en": "Blah blah" + }, + "name": { + "en": "Analytics" + }, + "order": 0 + } + } + }, + "dataLayer": true, + "debugKey": "butter", + "dlp": [], + "historyChange": true, + "invalidKey": "cheese", + "settings": { + "autoInjectScript": true + }, + "tools": { + "PBQr": { + "blockingTriggers": [], + "component": "html", + "defaultFields": {}, + "defaultPurpose": "rJJC", + "enabled": true, + "mode": { + "cloud": false, + "ignoreSPA": true, + "light": false, + "sample": false, + "segment": { + "end": 100, + "start": 0 + }, + "trigger": "pageload" + }, + "name": "Custom HTML", + "neoEvents": [ + { + "actionType": "event", + "blockingTriggers": [], + "data": { + "__zaraz_setting_name": "pageview1", + "htmlCode": "" + }, + "firingTriggers": [ + "Pageview" + ] + } + ], + "permissions": [ + "execute_unsafe_scripts" + ], + "settings": {}, + "type": "component" + } + }, + "triggers": { + "Pageview": { + "clientRules": [], + "description": "All page loads", + "excludeRules": [], + "loadRules": [ + { + "match": "{{ client.__zarazTrack }}", + "op": "EQUALS", + "value": "Pageview" + } + ], + "name": "Pageview", + "system": "pageload" + }, + "TFOl": { + "description": "", + "excludeRules": [], + "loadRules": [ + { + "id": "Kqsc", + "match": "test", + "op": "CONTAINS", + "value": "test" + }, + { + "action": "clickListener", + "id": "EDnV", + "settings": { + "selector": "test", + "type": "css", + "waitForTags": 0 + } + } + ], + "name": "test" + } + }, + "variables": { + "jwIx": { + "name": "test", + "type": "string", + "value": "sss" + }, + "pAuL": { + "name": "test-worker-var", + "type": "worker", + "value": { + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf" + } + } + }, + "zarazVersion": 44 + } + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/config", handler) + payload := UpdateZarazConfigParams{ + DebugKey: "cheese", + ZarazVersion: 44, + DataLayer: &trueValue, + Dlp: []any{}, + HistoryChange: &trueValue, + Settings: ZarazConfigSettings{ + AutoInjectScript: &trueValue, + }, + Tools: map[string]ZarazTool{ + "PBQr": { + BlockingTriggers: []string{}, + Enabled: &trueValue, + DefaultFields: map[string]any{}, + Name: "Custom HTML", + NeoEvents: []ZarazNeoEvent{ + { + ActionType: "event", + BlockingTriggers: []string{}, + Data: map[string]any{ + "__zaraz_setting_name": "pageview1", + "htmlCode": "", + }, + FiringTriggers: []string{"Pageview"}, + }, + }, + Type: ZarazToolComponent, + DefaultPurpose: "rJJC", + Component: "html", + Permissions: []string{"execute_unsafe_scripts"}, + Settings: map[string]any{}, + }, + }, + Triggers: map[string]ZarazTrigger{ + "Pageview": { + Name: "Pageview", + Description: "All page loads", + LoadRules: []ZarazTriggerRule{{Match: "{{ client.__zarazTrack }}", Op: "EQUALS", Value: "Pageview"}}, + ExcludeRules: []ZarazTriggerRule{}, + ClientRules: []any{}, + System: ZarazPageload, + }, + "TFOl": { + Name: "test", + Description: "", + LoadRules: []ZarazTriggerRule{{Id: "Kqsc", Match: "test", Op: "CONTAINS", Value: "test"}, {Id: "EDnV", Action: ZarazClickListener, Settings: ZarazRuleSettings{Selector: "test", Type: ZarazCSS}}}, + ExcludeRules: []ZarazTriggerRule{}, + }, + }, + Variables: map[string]ZarazVariable{ + "jwIx": { + Name: "test", + Type: ZarazVarString, + Value: "sss", + }, + "pAuL": { + Name: "test-worker-var", + Type: ZarazVarWorker, + Value: map[string]interface{}{ + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf", + }, + }, + }, + Consent: ZarazConsent{ + Enabled: &trueValue, + ButtonTextTranslations: ZarazButtonTextTranslations{ + AcceptAll: map[string]string{"en": "Accept ALL"}, + ConfirmMyChoices: map[string]string{"en": "YES!"}, + RejectAll: map[string]string{"en": "Reject ALL"}, + }, + CompanyEmail: "email@example.com", + ConsentModalIntroHTMLWithTranslations: map[string]string{"en": "Lorem ipsum dolar set Amet?"}, + CookieName: "zaraz-consent", + CustomCSS: ".test {\n color: red;\n}", + CustomIntroDisclaimerDismissed: &trueValue, + DefaultLanguage: "en", + HideModal: &falseValue, + PurposesWithTranslations: map[string]ZarazPurposeWithTranslations{ + "rJJC": { + Description: map[string]string{"en": "Blah blah"}, + Name: map[string]string{"en": "Analytics"}, + Order: 0, + }, + }, + }, + } + payload.DebugKey = "butter" // Updating config + modifiedConfig := expectedConfig + modifiedConfig.DebugKey = "butter" // Updating config + expected := ZarazConfigResponse{ + Result: modifiedConfig, + } + + actual, err := client.UpdateZarazConfig(context.Background(), ZoneIdentifier(testZoneID), payload) + require.NoError(t, err) + + assert.Equal(t, expected.Result, actual.Result) +} + +func TestGetZarazWorkflow(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": "realtime" + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/workflow", handler) + want := ZarazWorkflowResponse{ + Result: "realtime", + Response: Response{ + Success: true, + Messages: []ResponseInfo{}, + Errors: []ResponseInfo{}, + }, + } + + actual, err := client.GetZarazWorkflow(context.Background(), ZoneIdentifier(testZoneID)) + + require.NoError(t, err) + + assert.Equal(t, want, actual) +} + +func TestUpdateZarazWorkflow(t *testing.T) { + setup() + defer teardown() + + payload := UpdateZarazWorkflowParams{ + Workflow: "realtime", + } + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) + body, _ := io.ReadAll(r.Body) + bodyString := string(body) + assert.Equal(t, fmt.Sprintf("\"%s\"", payload.Workflow), bodyString) + + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": "realtime" + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/workflow", handler) + want := ZarazWorkflowResponse{ + Result: "realtime", + Response: Response{ + Success: true, + Messages: []ResponseInfo{}, + Errors: []ResponseInfo{}, + }, + } + + actual, err := client.UpdateZarazWorkflow(context.Background(), ZoneIdentifier(testZoneID), payload) + + require.NoError(t, err) + + assert.Equal(t, want, actual) +} + +func TestPublishZarazConfig(t *testing.T) { + setup() + defer teardown() + + payload := PublishZarazConfigParams{ + Description: "test description", + } + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) + body, _ := io.ReadAll(r.Body) + bodyString := string(body) + assert.Equal(t, fmt.Sprintf("\"%s\"", payload.Description), bodyString) + + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": "Config has been published successfully" + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/publish", handler) + want := ZarazPublishResponse{ + Result: "Config has been published successfully", + Response: Response{ + Success: true, + Messages: []ResponseInfo{}, + Errors: []ResponseInfo{}, + }, + } + + actual, err := client.PublishZarazConfig(context.Background(), ZoneIdentifier(testZoneID), payload) + + require.NoError(t, err) + + assert.Equal(t, want, actual) +} + +func TestGetZarazConfigHistoryList(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "result": [ + { + "createdAt": "2023-01-01T05:20:00Z", + "description": "test 1", + "id": 1005736, + "updatedAt": "2023-01-01T05:20:00Z", + "userId": "9ceddf6f117afe04c64716c83468d3a4" + }, + { + "createdAt": "2023-01-01T05:20:00Z", + "description": "test 2", + "id": 1005735, + "updatedAt": "2023-01-01T05:20:00Z", + "userId": "9ceddf6f117afe04c64716c83468d3a4" + } + ], + "success": true, + "errors": [], + "messages": [], + "result_info": { + "page": 1, + "per_page": 2, + "count": 2, + "total_count": 8 + } + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/history", handler) + createdAt, _ := time.Parse(time.RFC3339, "2023-01-01T05:20:00Z") + updatedAt, _ := time.Parse(time.RFC3339, "2023-01-01T05:20:00Z") + want := []ZarazHistoryRecord{ + { + CreatedAt: &createdAt, + Description: "test 1", + ID: 1005736, + UpdatedAt: &updatedAt, + UserID: "9ceddf6f117afe04c64716c83468d3a4", + }, + { + CreatedAt: &createdAt, + Description: "test 2", + ID: 1005735, + UpdatedAt: &updatedAt, + UserID: "9ceddf6f117afe04c64716c83468d3a4", + }, + } + + actual, _, err := client.ListZarazConfigHistory(context.Background(), ZoneIdentifier(testZoneID), ListZarazConfigHistoryParams{ + ResultInfo: ResultInfo{ + PerPage: 2, + }, + }) + + require.NoError(t, err) + + assert.Equal(t, want, actual) +} + +func TestGetDefaultZarazConfig(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + + w.Header().Set("content-type", "text/plain") + fmt.Fprint(w, `{ + "someTestKeyThatRepsTheConfig": "test" + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/default", handler) + + _, err := client.GetDefaultZarazConfig(context.Background(), ZoneIdentifier(testZoneID)) + require.NoError(t, err) +} + +func TestExportZarazConfig(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + + w.Header().Set("content-type", "text/plain") + fmt.Fprint(w, `{ + "someTestKeyThatRepsTheConfig": "test" + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/export", handler) + + err := client.ExportZarazConfig(context.Background(), ZoneIdentifier(testZoneID)) + require.NoError(t, err) +}