<commit_before>package kit

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var apiLimit = newRateLimiter(time.Second / 2)

type httpClient struct {
	client *http.Client
	config Configuration
}

type requestType int

const (
	themeRequest requestType = iota
	assetRequest
	listRequest
)

func newHTTPClient(config Configuration) (*httpClient, error) {
	client := &httpClient{
		client: &http.Client{Timeout: config.Timeout},
		config: config,
	}

	if len(config.Proxy) > 0 {
		LogWarnf("Proxy URL detected from Configuration: %s", config.Proxy)
		LogWarn("SSL Certificate Validation will be disabled!")
		proxyURL, err := url.Parse(config.Proxy)
		if err != nil {
			return client, err
		}
		client.client.Transport = &http.Transport{
			Proxy:           http.ProxyURL(proxyURL),
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	return client, nil
}

// AdminURL will return the url to the shopify admin.
func (client *httpClient) AdminURL() string {
	adminURL := fmt.Sprintf("%s/admin", client.config.Domain)
	if !client.config.IsLive() {
		if themeID, err := strconv.ParseInt(client.config.ThemeID, 10, 64); err == nil {
			adminURL = fmt.Sprintf("%s/themes/%d", adminURL, themeID)
		}
	}
	parsedURL, _ := url.Parse(adminURL)
	parsedURL.Scheme = "https"
	if strings.HasPrefix(client.config.Domain, "http") {
		parsedURL.Scheme = "http"
	}
	return parsedURL.String()
}

// AssetPath will return the assets endpoint in the admin section of shopify.
func (client *httpClient) AssetPath() string {
	return fmt.Sprintf("%s/assets.json", client.AdminURL())
}

// ThemesPath will return the endpoint of the themes interactions.
func (client *httpClient) ThemesPath() string {
	return fmt.Sprintf("%s/themes.json", client.AdminURL())
}

// ThemePath will return the endpoint of the a single theme.
func (client *httpClient) ThemePath(themeID int64) string {
	return fmt.Sprintf("%s/themes/%d.json", client.AdminURL(), themeID)
}

func (client *httpClient) AssetQuery(event EventType, query map[string]string) (*ShopifyResponse, Error) {
	path := fmt.Sprintf("%s?fields=key,attachment,value", client.AssetPath())
	for key, value := range query {
		path += "&" + key + "=" + value
	}
	rtype := listRequest
	if len(query) > 0 {
		rtype = assetRequest
	}
	return client.sendRequest(rtype, event, path, nil)
}

func (client *httpClient) NewTheme(name, source string) (*ShopifyResponse, Error) {
	return client.sendJSON(themeRequest, Create, client.ThemesPath(), map[string]interface{}{
		"theme": Theme{Name: name, Source: source, Role: "unpublished"},
	})
}

func (client *httpClient) GetTheme(themeID int64) (*ShopifyResponse, Error) {
	return client.sendRequest(themeRequest, Retrieve, client.ThemePath(themeID), nil)
}

func (client *httpClient) AssetAction(event EventType, asset Asset) (*ShopifyResponse, Error) {
	resp, _ := client.sendJSON(assetRequest, event, client.AssetPath(), map[string]interface{}{
		"asset": asset,
	})
	// If there were any errors the asset is nil so lets set it and reformat errors
	resp.Asset = asset
	return resp, resp.Error()
}

func (client *httpClient) newRequest(event EventType, urlStr string, body io.Reader) (*http.Request, Error) {
	req, err := http.NewRequest(event.toMethod(), urlStr, body)
	if err != nil {
		return nil, kitError{err}
	}

	req.Header.Add("X-Shopify-Access-Token", client.config.Password)
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")
	req.Header.Add("User-Agent", fmt.Sprintf("go/themekit (%s; %s)", runtime.GOOS, runtime.GOARCH))

	return req, nil
}

func (client *httpClient) sendJSON(rtype requestType, event EventType, urlStr string, body map[string]interface{}) (*ShopifyResponse, Error) {
	data, err := json.Marshal(body)
	if err != nil {
		return nil, kitError{err}
	}
	return client.sendRequest(rtype, event, urlStr, bytes.NewBuffer(data))
}

func (client *httpClient) sendRequest(rtype requestType, event EventType, urlStr string, body io.Reader) (*ShopifyResponse, Error) {
	req, err := client.newRequest(event, urlStr, body)
	if err != nil {<commit_msg>Fixing a bug where the shopify response was null and theme kit tried to set attributes on the response<commit_after>package kit

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var apiLimit = newRateLimiter(time.Second / 2)

type httpClient struct {
	client *http.Client
	config Configuration
}

type requestType int

const (
	themeRequest requestType = iota
	assetRequest
	listRequest
)

func newHTTPClient(config Configuration) (*httpClient, error) {
	client := &httpClient{
		client: &http.Client{Timeout: config.Timeout},
		config: config,
	}

	if len(config.Proxy) > 0 {
		LogWarnf("Proxy URL detected from Configuration: %s", config.Proxy)
		LogWarn("SSL Certificate Validation will be disabled!")
		proxyURL, err := url.Parse(config.Proxy)
		if err != nil {
			return client, err
		}
		client.client.Transport = &http.Transport{
			Proxy:           http.ProxyURL(proxyURL),
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	return client, nil
}

// AdminURL will return the url to the shopify admin.
func (client *httpClient) AdminURL() string {
	adminURL := fmt.Sprintf("%s/admin", client.config.Domain)
	if !client.config.IsLive() {
		if themeID, err := strconv.ParseInt(client.config.ThemeID, 10, 64); err == nil {
			adminURL = fmt.Sprintf("%s/themes/%d", adminURL, themeID)
		}
	}
	parsedURL, _ := url.Parse(adminURL)
	parsedURL.Scheme = "https"
	if strings.HasPrefix(client.config.Domain, "http") {
		parsedURL.Scheme = "http"
	}
	return parsedURL.String()
}

// AssetPath will return the assets endpoint in the admin section of shopify.
func (client *httpClient) AssetPath() string {
	return fmt.Sprintf("%s/assets.json", client.AdminURL())
}

// ThemesPath will return the endpoint of the themes interactions.
func (client *httpClient) ThemesPath() string {
	return fmt.Sprintf("%s/themes.json", client.AdminURL())
}

// ThemePath will return the endpoint of the a single theme.
func (client *httpClient) ThemePath(themeID int64) string {
	return fmt.Sprintf("%s/themes/%d.json", client.AdminURL(), themeID)
}

func (client *httpClient) AssetQuery(event EventType, query map[string]string) (*ShopifyResponse, Error) {
	path := fmt.Sprintf("%s?fields=key,attachment,value", client.AssetPath())
	for key, value := range query {
		path += "&" + key + "=" + value
	}
	rtype := listRequest
	if len(query) > 0 {
		rtype = assetRequest
	}
	return client.sendRequest(rtype, event, path, nil)
}

func (client *httpClient) NewTheme(name, source string) (*ShopifyResponse, Error) {
	return client.sendJSON(themeRequest, Create, client.ThemesPath(), map[string]interface{}{
		"theme": Theme{Name: name, Source: source, Role: "unpublished"},
	})
}

func (client *httpClient) GetTheme(themeID int64) (*ShopifyResponse, Error) {
	return client.sendRequest(themeRequest, Retrieve, client.ThemePath(themeID), nil)
}

func (client *httpClient) AssetAction(event EventType, asset Asset) (*ShopifyResponse, Error) {
	resp, err := client.sendJSON(assetRequest, event, client.AssetPath(), map[string]interface{}{
		"asset": asset,
	})
	if resp == nil {
		return resp, err
	}
	// If there were any errors the asset is nil so lets set it and reformat errors
	resp.Asset = asset
	return resp, resp.Error()
}

func (client *httpClient) newRequest(event EventType, urlStr string, body io.Reader) (*http.Request, Error) {
	req, err := http.NewRequest(event.toMethod(), urlStr, body)
	if err != nil {
		return nil, kitError{err}
	}

	req.Header.Add("X-Shopify-Access-Token", client.config.Password)
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json")
	req.Header.Add("User-Agent", fmt.Sprintf("go/themekit (%s; %s)", runtime.GOOS, runtime.GOARCH))

	return req, nil
}

func (client *httpClient) sendJSON(rtype requestType, event EventType, urlStr string, body map[string]interface{}) (*ShopifyResponse, Error) {
	data, err := json.Marshal(body)
	if err != nil {
		return nil, kitError{err}
	}
	return client.sendRequest(rtype, event, urlStr, bytes.NewBuffer(data))
}

func (client *httpClient) sendRequest(rtype requestType, event EventType, urlStr string, body io.Reader) (*ShopifyResponse, Error) {
	req, err := client.newRequest(event, urlStr, body)
	if err != nil {
{'fraction_non_alphanumeric': 0.13897744716023144, 'fraction_numerical': 0.002597709292714606, 'mean_word_length': 4.890125173852573, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4581353', 'n_tokens_mistral': 2850, 'n_tokens_neox': 2758, 'n_words': 757}