diff --git a/go.mod b/go.mod index b2158ce..0e1d138 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,10 @@ module gitlab.com/ekzyis/hnbot go 1.20 require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/namsral/flag v1.7.4-pre // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.8.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4c16f8b..893bfa6 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,20 @@ +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= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs= github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sn.go b/sn.go index 0722d2e..7d801a1 100644 --- a/sn.go +++ b/sn.go @@ -13,6 +13,18 @@ type GraphQLPayload struct { Variables map[string]interface{} `json:"variables,omitempty"` } +type Dupe struct { + Id int `json:"id,string"` + Url string `json:"url"` + Title string `json:"title"` +} + +type DupesResponse struct { + Data struct { + Dupes []Dupe `json:"dupes"` + } `json:"data"` +} + func filterByRelevanceForSN(stories *[]Story) *[]Story { // TODO: filter by relevance @@ -20,8 +32,55 @@ func filterByRelevanceForSN(stories *[]Story) *[]Story { return &slice } +func fetchDupes(url string) *[]Dupe { + body := GraphQLPayload{ + Query: ` + query Dupes($url: String!) { + dupes(url: $url) { + id + url + title + } + }`, + Variables: map[string]interface{}{ + "url": url, + }, + } + + bodyJSON, err := json.Marshal(body) + if err != nil { + log.Fatal("Error during json.Marshal:", err) + } + + apiUrl := "https://stacker.news/api/graphql" + req, err := http.NewRequest("POST", apiUrl, bytes.NewBuffer(bodyJSON)) + if err != nil { + panic(err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Cookie", fmt.Sprintf("__Host-next-auth.csrf-token=%s", SnApiToken)) + + client := http.DefaultClient + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + var dupesResp DupesResponse + err = json.NewDecoder(resp.Body).Decode(&dupesResp) + if err != nil { + log.Fatal("Error decoding dupes JSON:", err) + } + + return &dupesResp.Data.Dupes +} + func postToSN(story *Story) { - // TODO: check for dupes first + dupes := fetchDupes(story.Url) + if len(*dupes) > 0 { + return + } body := GraphQLPayload{ Query: ` @@ -42,8 +101,8 @@ func postToSN(story *Story) { log.Fatal("Error during json.Marshal:", err) } - url := "https://stacker.news/api/graphql" - req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyJSON)) + apiUrl := "https://stacker.news/api/graphql" + req, err := http.NewRequest("POST", apiUrl, bytes.NewBuffer(bodyJSON)) if err != nil { panic(err) } @@ -57,5 +116,5 @@ func postToSN(story *Story) { } defer resp.Body.Close() - log.Printf("POST %s %d\n", url, resp.StatusCode) + log.Printf("POST %s %d\n", apiUrl, resp.StatusCode) } diff --git a/sn_test.go b/sn_test.go new file mode 100644 index 0000000..020e5cc --- /dev/null +++ b/sn_test.go @@ -0,0 +1,14 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFetchDupes(t *testing.T) { + // TODO: mock HTTP request + url := "https://en.wikipedia.org/wiki/Dishwasher_salmon" + dupes := fetchDupes(url) + assert.NotEmpty(t, *dupes, "Expected at least one duplicate") +}