Skip to content

Commit

Permalink
add GetClaims endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
joshraphael committed Nov 24, 2024
1 parent 639066c commit bbe5d93
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 3 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@ For convenience, the API docs and examples can be found in the tables below
|Function|Description|Links|
|-|-|-|
|`GetRecentGameAwards()`|Gets all recently granted game awards across the site's userbase.|[docs](https://api-docs.retroachievements.org/v1/get-recent-game-awards.html) \| [example](examples/feed/getrecentgameawards/getrecentgameawards.go)|
|`GetActiveClaims()`|Gets information about all active set claims (max: 1000).|[docs](https://api-docs.retroachievements.org/v1/get-active-claims.html) \| [example](examples/feed/getactiveclaims/getactiveclaims.go)|
|`GetActiveClaims()`|Gets information about all active set claims (max: 1000).|[docs](https://api-docs.retroachievements.org/v1/get-active-claims.html) \| [example](examples/feed/getactiveclaims/getactiveclaims.go)|
|`GetClaims()`|Gets information about all achievement set development claims of a specified kind: completed, dropped, or expired (max: 1000).|[docs](https://api-docs.retroachievements.org/v1/get-claims.html) \| [example](examples/feed/getclaims/getclaims.go)|
28 changes: 28 additions & 0 deletions examples/feed/getclaims/getclaims.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Package getclaims provides an example for getting information about all achievement set development claims of a specified kind: completed, dropped, or expired (max: 1000).
package main

import (
"fmt"
"os"

"github.com/joshraphael/go-retroachievements"
"github.com/joshraphael/go-retroachievements/models"
)

/*
Test script, add RA_API_KEY to your env and use `go run getclaims.go`
*/
func main() {
secret := os.Getenv("RA_API_KEY")

client := retroachievements.NewClient(secret)

resp, err := client.GetClaims(models.GetClaimsParameters{
Kind: &models.GetClaimsParametersKindDropped{},
})
if err != nil {
panic(err)
}

fmt.Printf("%+v\n", resp)
}
24 changes: 24 additions & 0 deletions feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package retroachievements
import (
"fmt"
"net/http"
"strconv"

raHttp "github.com/joshraphael/go-retroachievements/http"
"github.com/joshraphael/go-retroachievements/models"
Expand Down Expand Up @@ -73,3 +74,26 @@ func (c *Client) GetActiveClaims(params models.GetActiveClaimsParameters) ([]mod
}
return resp, nil
}

// GetClaims gets information about all achievement set development claims of a specified kind: completed, dropped, or expired (max: 1000).
func (c *Client) GetClaims(params models.GetClaimsParameters) ([]models.GetClaims, error) {
details := []raHttp.RequestDetail{
raHttp.Method(http.MethodGet),
raHttp.Path("/API/API_GetClaims.php"),
raHttp.APIToken(c.Secret),
}
if params.Kind != nil {
details = append(details, raHttp.K([]string{
strconv.Itoa(params.Kind.GetClaimsParametersKindID()),
}))
}
r, err := c.do(details...)
if err != nil {
return nil, fmt.Errorf("calling endpoint: %w", err)
}
resp, err := raHttp.ResponseList[models.GetClaims](r)
if err != nil {
return nil, fmt.Errorf("parsing response list: %w", err)
}
return resp, nil
}
149 changes: 149 additions & 0 deletions feed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,152 @@ func TestGetActiveClaims(tt *testing.T) {
})
}
}

func TestGetClaims(tt *testing.T) {
created, err := time.Parse(time.DateTime, "2024-11-24 13:45:14")
require.NoError(tt, err)
doneTime, err := time.Parse(time.DateTime, "2025-02-24 13:45:14")
require.NoError(tt, err)
update, err := time.Parse(time.DateTime, "2024-11-24 13:45:14")
require.NoError(tt, err)
tests := []struct {
name string
params models.GetClaimsParameters
modifyURL func(url string) string
responseCode int
responseMessage []models.GetClaims
responseError models.ErrorResponse
response func(messageBytes []byte, errorBytes []byte) []byte
assert func(t *testing.T, resp []models.GetClaims, err error)
}{
{
name: "fail to call endpoint",
params: models.GetClaimsParameters{
Kind: &models.GetClaimsParametersKindDropped{},
},
modifyURL: func(url string) string {
return ""
},
responseCode: http.StatusOK,
response: func(messageBytes []byte, errorBytes []byte) []byte {
return messageBytes
},
assert: func(t *testing.T, resp []models.GetClaims, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetClaims.php?k=2&y=some_secret\": unsupported protocol scheme \"\"")
},
},
{
name: "error response",
params: models.GetClaimsParameters{
Kind: &models.GetClaimsParametersKindCompleted{},
},
modifyURL: func(url string) string {
return url
},
responseCode: http.StatusUnauthorized,
responseError: models.ErrorResponse{
Message: "test",
Errors: []models.ErrorDetail{
{
Status: http.StatusUnauthorized,
Code: "unauthorized",
Title: "Not Authorized",
},
},
},
response: func(messageBytes []byte, errorBytes []byte) []byte {
return errorBytes
},
assert: func(t *testing.T, resp []models.GetClaims, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "parsing response list: error code 401 returned: {\"message\":\"test\",\"errors\":[{\"status\":401,\"code\":\"unauthorized\",\"title\":\"Not Authorized\"}]}")
},
},
{
name: "success",
params: models.GetClaimsParameters{
Kind: &models.GetClaimsParametersKindCompleted{},
},
modifyURL: func(url string) string {
return url
},
responseCode: http.StatusOK,
responseMessage: []models.GetClaims{
{
ID: 14667,
User: "Tayadaoc",
GameID: 29805,
GameTitle: "Tetras",
GameIcon: "/Images/097197.png",
ConsoleID: 47,
ConsoleName: "PC-8000/8800",
ClaimType: 0,
SetType: 0,
Status: 0,
Extension: 0,
Special: 0,
Created: models.DateTime{
Time: created,
},
DoneTime: models.DateTime{
Time: doneTime,
},
Updated: models.DateTime{
Time: update,
},
UserIsJrDev: 0,
MinutesLeft: 132413,
},
},
response: func(messageBytes []byte, errorBytes []byte) []byte {
return messageBytes
},
assert: func(t *testing.T, resp []models.GetClaims, err error) {
require.NotNil(t, resp)
require.Len(t, resp, 1)
require.Equal(t, 14667, resp[0].ID)
require.Equal(t, "Tayadaoc", resp[0].User)
require.Equal(t, 29805, resp[0].GameID)
require.Equal(t, "Tetras", resp[0].GameTitle)
require.Equal(t, "/Images/097197.png", resp[0].GameIcon)
require.Equal(t, 47, resp[0].ConsoleID)
require.Equal(t, "PC-8000/8800", resp[0].ConsoleName)
require.Equal(t, 0, resp[0].ClaimType)
require.Equal(t, 0, resp[0].SetType)
require.Equal(t, 0, resp[0].Status)
require.Equal(t, 0, resp[0].Extension)
require.Equal(t, 0, resp[0].Special)
require.Equal(t, created, resp[0].Created.Time)
require.Equal(t, doneTime, resp[0].DoneTime.Time)
require.Equal(t, update, resp[0].Updated.Time)
require.Equal(t, 0, resp[0].UserIsJrDev)
require.Equal(t, 132413, resp[0].MinutesLeft)
require.NoError(t, err)
},
},
}
for _, test := range tests {
tt.Run(test.name, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
expectedPath := "/API/API_GetClaims.php"
if r.URL.Path != expectedPath {
t.Errorf("Expected to request '%s', got: %s", expectedPath, r.URL.Path)
}
w.WriteHeader(test.responseCode)
messageBytes, err := json.Marshal(test.responseMessage)
require.NoError(t, err)
errBytes, err := json.Marshal(test.responseError)
require.NoError(t, err)
resp := test.response(messageBytes, errBytes)
num, err := w.Write(resp)
require.NoError(t, err)
require.Equal(t, num, len(resp))
}))
defer server.Close()
client := retroachievements.New(test.modifyURL(server.URL), "go-retroachievements/v0.0.0", "some_secret")
resp, err := client.GetClaims(test.params)
test.assert(t, resp, err)
})
}
}
50 changes: 48 additions & 2 deletions models/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,57 @@ type GetRecentGameAwardsResult struct {
ConsoleID int `json:"ConsoleID"`
ConsoleName string `json:"ConsoleName"`
}
type GetActiveClaimsParameters struct{}

type GetActiveClaimsParameters struct {
type GetActiveClaims struct {
ID int `json:"ID"`
User string `json:"User"`
GameID int `json:"GameID"`
GameTitle string `json:"GameTitle"`
GameIcon string `json:"GameIcon"`
ConsoleID int `json:"ConsoleID"`
ConsoleName string `json:"ConsoleName"`
ClaimType int `json:"ClaimType"`
SetType int `json:"SetType"`
Status int `json:"Status"`
Extension int `json:"Extension"`
Special int `json:"Special"`
Created DateTime `json:"Created"`
DoneTime DateTime `json:"DoneTime"`
Updated DateTime `json:"Updated"`
UserIsJrDev int `json:"UserIsJrDev"`
MinutesLeft int `json:"MinutesLeft"`
}

type GetActiveClaims struct {
type GetClaimsParametersKind interface {
GetClaimsParametersKindID() int
}

type GetClaimsParametersKindCompleted struct{}

func (c *GetClaimsParametersKindCompleted) GetClaimsParametersKindID() int {
return 1
}

type GetClaimsParametersKindDropped struct{}

func (d *GetClaimsParametersKindDropped) GetClaimsParametersKindID() int {
return 2
}

// NOTE: Expired claims returns a strange format different from the rest, disabling it for now as there is not many available
// type GetClaimsParametersKindExpired struct{}

// func (e *GetClaimsParametersKindExpired) GetClaimsParametersKindID() int {
// return 3
// }

type GetClaimsParameters struct {
// [Optional] The desired claim kind: completed, dropped, or expired (default: completed).
Kind GetClaimsParametersKind
}

type GetClaims struct {
ID int `json:"ID"`
User string `json:"User"`
GameID int `json:"GameID"`
Expand Down

0 comments on commit bbe5d93

Please sign in to comment.