diff --git a/tests/cache_test.go b/caching/cache_test.go similarity index 52% rename from tests/cache_test.go rename to caching/cache_test.go index 0ddf858..f937395 100644 --- a/tests/cache_test.go +++ b/caching/cache_test.go @@ -1,14 +1,19 @@ -package tests +package caching import ( - "github.com/flygrounder/go-mtg-vk/caching" - "github.com/stretchr/testify/assert" + "fmt" "testing" "time" + + "github.com/alicebob/miniredis/v2" + "github.com/go-redis/redis" + "github.com/stretchr/testify/assert" ) func TestGetSet(t *testing.T) { - client := getTestClient() + client, s := getTestClient() + defer s.Close() + keyName := "test_key" value := "test_value" client.Set(keyName, value) @@ -18,19 +23,27 @@ func TestGetSet(t *testing.T) { } func TestExpiration(t *testing.T) { - client := getTestClient() + client, s := getTestClient() + defer s.Close() + client.Expiration = time.Millisecond keyName := "test_key" value := "test_value" client.Set(keyName, value) - time.Sleep(time.Millisecond * 2) + s.FastForward(time.Millisecond * 2) val, err := client.Get(keyName) assert.Zero(t, val) assert.NotNil(t, err) } -func getTestClient() *caching.CacheClient { - client := new(caching.CacheClient) - client.Init() - return client +func getTestClient() (*CacheClient, *miniredis.Miniredis) { + s, _ := miniredis.Run() + fmt.Println(s.Addr()) + c := redis.NewClient(&redis.Options{ + Addr: s.Addr(), + }) + return &CacheClient{ + Storage: c, + Expiration: 0, + }, s } diff --git a/caching/client.go b/caching/client.go index f0f0adc..f34263d 100644 --- a/caching/client.go +++ b/caching/client.go @@ -6,7 +6,7 @@ import ( ) type CacheClient struct { - storage *redis.Client + Storage *redis.Client Expiration time.Duration } @@ -22,7 +22,7 @@ func GetClient() *CacheClient { } func (client *CacheClient) Init() { - client.storage = redis.NewClient(&redis.Options{ + client.Storage = redis.NewClient(&redis.Options{ Addr: HostName, Password: Password, DB: 0, @@ -31,9 +31,9 @@ func (client *CacheClient) Init() { } func (client *CacheClient) Set(key string, value string) { - client.storage.Set(key, value, client.Expiration) + client.Storage.Set(key, value, client.Expiration) } func (client *CacheClient) Get(key string) (string, error) { - return client.storage.Get(key).Result() + return client.Storage.Get(key).Result() } diff --git a/cardsinfo/format.go b/cardsinfo/format.go index ba78791..a575b65 100644 --- a/cardsinfo/format.go +++ b/cardsinfo/format.go @@ -8,15 +8,7 @@ func FormatCardPrices(name string, prices []CardPrice) string { message := fmt.Sprintf("Оригинальное название: %v\n", name) message += fmt.Sprintf("Результатов: %v\n", len(prices)) for i, v := range prices { - message += fmt.Sprintf("%v. %v\nRegular: %v\nFoil: %v\n", i+1, v.Edition, formatPrice(v.Price), formatPrice(v.PriceFoil)) - message += fmt.Sprintf("%v\n", v.Link) + message += fmt.Sprintf("%v. %v", i + 1, v.Format()) } return message } - -func formatPrice(price string) string { - if price == "" { - return "-" - } - return fmt.Sprintf("$%v", price) -} diff --git a/tests/names_test.go b/cardsinfo/names_test.go similarity index 62% rename from tests/names_test.go rename to cardsinfo/names_test.go index 3ef4890..b53b455 100644 --- a/tests/names_test.go +++ b/cardsinfo/names_test.go @@ -1,47 +1,46 @@ -package tests +package cardsinfo import ( - "github.com/flygrounder/go-mtg-vk/cardsinfo" "github.com/stretchr/testify/assert" "testing" ) func TestGetCardByStringFull(t *testing.T) { - name := cardsinfo.GetOriginalName("Шок") + name := GetOriginalName("Шок") assert.Equal(t, "Shock", name) } func TestGetCardByStringSplit(t *testing.T) { - name := cardsinfo.GetOriginalName("commit") + name := GetOriginalName("commit") assert.Equal(t, "Commit // Memory", name) } func TestGetCardByStringDouble(t *testing.T) { - name := cardsinfo.GetOriginalName("Legion's landing") + name := GetOriginalName("Legion's landing") assert.Equal(t, "Legion's Landing | Adanto, the First Fort", name) } func TestGetCardByStringPrefix(t *testing.T) { - name := cardsinfo.GetOriginalName("Тефери, герой") + name := GetOriginalName("Тефери, герой") assert.Equal(t, "Teferi, Hero of Dominaria", name) } func TestGetCardByStringEnglish(t *testing.T) { - name := cardsinfo.GetOriginalName("Teferi, Hero of Dominaria") + name := GetOriginalName("Teferi, Hero of Dominaria") assert.Equal(t, "Teferi, Hero of Dominaria", name) } func TestGetCardByStringWrong(t *testing.T) { - name := cardsinfo.GetOriginalName("fwijefiwjfew") + name := GetOriginalName("fwijefiwjfew") assert.Equal(t, "", name) } func TestGetCardBySetId(t *testing.T) { - name := cardsinfo.GetNameByCardId("DOM", "207") + name := GetNameByCardId("DOM", "207") assert.Equal(t, "Teferi, Hero of Dominaria", name) } func TestGetCardBySetIdWrong(t *testing.T) { - name := cardsinfo.GetNameByCardId("DOM", "1207") + name := GetNameByCardId("DOM", "1207") assert.Equal(t, "", name) } diff --git a/tests/price_format_test.go b/cardsinfo/price_format_test.go similarity index 72% rename from tests/price_format_test.go rename to cardsinfo/price_format_test.go index 28f0332..341a2fd 100644 --- a/tests/price_format_test.go +++ b/cardsinfo/price_format_test.go @@ -1,27 +1,26 @@ -package tests +package cardsinfo import ( - "github.com/flygrounder/go-mtg-vk/cardsinfo" "github.com/stretchr/testify/assert" "testing" ) func TestFormat(t *testing.T) { - data := []cardsinfo.CardPrice{ - { + data := []CardPrice{ + &TcgCardPrice{ Name: "Green lotus", PriceFoil: "22.8", Link: "scg.com/1", Edition: "alpha", }, - { + &TcgCardPrice{ Name: "White lotus", Price: "3.22", Link: "scg.com/2", Edition: "gamma", }, } - res := cardsinfo.FormatCardPrices("Black Lotus", data) + res := FormatCardPrices("Black Lotus", data) ans := "Оригинальное название: Black Lotus\nРезультатов: 2\n1. alpha\nRegular: -\nFoil: $22.8\nscg.com/1\n2. gamma\nRegular: $3.22\nFoil: -\nscg.com/2\n" - assert.Equal(t, res, ans) + assert.Equal(t, ans, res) } diff --git a/cardsinfo/prices.go b/cardsinfo/prices.go index 8a7ef41..5481374 100644 --- a/cardsinfo/prices.go +++ b/cardsinfo/prices.go @@ -1,14 +1,50 @@ package cardsinfo import ( - "fmt" "context" + "fmt" + "net/url" scryfall "github.com/BlueMonday/go-scryfall" + "github.com/antchfx/htmlquery" "github.com/pkg/errors" ) +const scgDomain = "https://starcitygames.com" +const scgSearchUrlTemplate = "https://starcitygames.hawksearch.com/sites/starcitygames/?search_query=%v" + func GetPrices(name string) ([]CardPrice, error) { + return GetPricesScg(name) +} + +func GetPricesScg(name string) ([]CardPrice, error) { + escapedName := url.QueryEscape(name) + searchUrl := fmt.Sprintf(scgSearchUrlTemplate, escapedName) + node, err := htmlquery.LoadURL(searchUrl) + if err != nil { + return nil, errors.Wrap(err, "cannot load url") + } + blocks := htmlquery.Find(node, "//div[@class=\"hawk-results-item\"]") + var results []CardPrice + for _, block := range blocks { + price := &ScgCardPrice{} + linkNode := htmlquery.FindOne(block, "//h2/a") + for _, attr := range linkNode.Attr { + if attr.Key == "href" { + price.Link = scgDomain + attr.Val + break + } + } + editionNode := htmlquery.FindOne(block, "//p[@class=\"hawk-results-item__category\"]/a") + price.Edition = editionNode.FirstChild.Data + priceNode := htmlquery.FindOne(block, "//div[contains(concat(' ',normalize-space(@class),' '),' hawk-results-item__options-table-cell--price ')]") + price.Price = priceNode.FirstChild.Data + results = append(results, price) + } + return results, nil +} + +func GetPricesTcg(name string) ([]CardPrice, error) { client, err := scryfall.NewClient() if err != nil { return nil, errors.Wrap(err, "Cannot fetch prices") @@ -24,7 +60,7 @@ func GetPrices(name string) ([]CardPrice, error) { if card.Prices.USD == "" && card.Prices.USDFoil == "" { continue } - cardPrice := CardPrice { + cardPrice := &TcgCardPrice { Edition: edition, Price: card.Prices.USD, PriceFoil: card.Prices.USDFoil, diff --git a/tests/prices_test.go b/cardsinfo/prices_test.go similarity index 50% rename from tests/prices_test.go rename to cardsinfo/prices_test.go index fd7182f..f85b70a 100644 --- a/tests/prices_test.go +++ b/cardsinfo/prices_test.go @@ -1,15 +1,13 @@ -package tests +package cardsinfo import ( - "fmt" - "github.com/flygrounder/go-mtg-vk/cardsinfo" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestParser(t *testing.T) { - prices, err := cardsinfo.GetPrices("Black lotus") - fmt.Println(prices) + prices, err := GetPrices("Black lotus") assert.Nil(t, err) assert.NotEmpty(t, prices) } diff --git a/cardsinfo/structs.go b/cardsinfo/structs.go index 1f41d91..4c49d98 100644 --- a/cardsinfo/structs.go +++ b/cardsinfo/structs.go @@ -1,10 +1,15 @@ package cardsinfo import ( + "fmt" "strings" ) -type CardPrice struct { +type CardPrice interface { + Format() string +} + +type TcgCardPrice struct { FullArt bool Name string Price string @@ -13,6 +18,27 @@ type CardPrice struct { Edition string } +func (t *TcgCardPrice) Format() string { + return fmt.Sprintf("%v\nRegular: %v\nFoil: %v\n%v\n", t.Edition, formatTcgPrice(t.Price), formatTcgPrice(t.PriceFoil), t.Link) +} + +func formatTcgPrice(price string) string { + if price == "" { + return "-" + } + return fmt.Sprintf("$%v", price) +} + +type ScgCardPrice struct { + Price string + Edition string + Link string +} + +func (s *ScgCardPrice) Format() string { + return fmt.Sprintf("%v: %v\n%v\n", s.Edition, s.Price, s.Link) +} + type Card struct { Name string `json:"name"` Layout string `json:"layout"` @@ -24,20 +50,3 @@ func (c *Card) getName() string { } return c.Name } - -type ScgResponse struct { - Response ScgResponseContainer `json:"response"` -} - -type ScgResponseContainer struct { - Data []ScgConditionContainer `json:"data"` -} - -type ScgConditionContainer struct { - Price float64 `json:"price"` - OptionValues []ScgCondition `json:"option_values"` -} - -type ScgCondition struct { - Label string `json:"label"` -} diff --git a/go.mod b/go.mod index e31abc9..7c1fe4b 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ -module github.com/flygrounder/go-mtg-vk +module gitlab.com/flygrounder/go-mtg-vk go 1.12 require ( github.com/BlueMonday/go-scryfall v0.1.0 + github.com/alicebob/miniredis/v2 v2.14.1 github.com/antchfx/htmlquery v1.0.0 github.com/antchfx/xpath v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -12,7 +13,8 @@ require ( github.com/onsi/ginkgo v1.10.3 // indirect github.com/onsi/gomega v1.7.1 // indirect github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.3.0 - golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 + github.com/stretchr/testify v1.5.1 + github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect + golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c // indirect ) diff --git a/go.sum b/go.sum index 93a05fa..1987d2b 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,16 @@ github.com/BlueMonday/go-scryfall v0.1.0 h1:AWbPrz3f1Ky6sDT5OAEiIFJjSsSTdPQYv2SqUyPbYjg= github.com/BlueMonday/go-scryfall v0.1.0/go.mod h1:8lDLilohikGawCpspnqY6pknEr+nccwHdwvLYZAzrEc= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.14.1 h1:GjlbSeoJ24bzdLRs13HoMEeaRZx9kg5nHoRW7QV/nCs= +github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= github.com/antchfx/htmlquery v1.0.0 h1:O5IXz8fZF3B3MW+B33MZWbTHBlYmcfw0BAxgErHuaMA= github.com/antchfx/htmlquery v1.0.0/go.mod h1:MS9yksVSQXls00iXkiMqXr0J+umL/AmxXKuP28SUJM8= github.com/antchfx/xpath v1.0.0 h1:Q5gFgh2O40VTSwMOVbFE7nFNRBu3tS21Tn0KAWeEjtk= github.com/antchfx/xpath v1.0.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -43,8 +50,13 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= +github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= @@ -53,6 +65,7 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/main.go b/main.go index 039ce7f..a492687 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/flygrounder/go-mtg-vk/vk" + "gitlab.com/flygrounder/go-mtg-vk/vk" "github.com/gin-gonic/gin" ) diff --git a/vk/handlers.go b/vk/handlers.go index b30da1d..0a89ab8 100644 --- a/vk/handlers.go +++ b/vk/handlers.go @@ -7,8 +7,8 @@ import ( "net/http" "strings" - "github.com/flygrounder/go-mtg-vk/caching" - "github.com/flygrounder/go-mtg-vk/cardsinfo" + "gitlab.com/flygrounder/go-mtg-vk/caching" + "gitlab.com/flygrounder/go-mtg-vk/cardsinfo" "github.com/gin-gonic/gin" )