Skip to content

Commit

Permalink
add GetUserCompletedGames
Browse files Browse the repository at this point in the history
  • Loading branch information
joshraphael committed Nov 17, 2024
1 parent d684187 commit b3c0762
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ For convenience, the API docs and examples can be found in the tables below
|`GetUserProgress()`|Get a user's progress on a list of specified games.|[docs](https://api-docs.retroachievements.org/v1/get-user-progress.html) \| [example](examples/user/getuserprogress/getuserprogress.go)|
|`GetUserRecentlyPlayedGames()`|Get a list of games a user has recently played.|[docs](https://api-docs.retroachievements.org/v1/get-user-recently-played-games.html) \| [example](examples/user/getuserrecentlyplayedgames/getuserrecentlyplayedgames.go)|
|`GetUserSummary()`|Get a user's profile metadata.|[docs](https://api-docs.retroachievements.org/v1/get-user-summary.html) \| [example](examples/user/getusersummary/getusersummary.go)|
|`GetUserCompletedGames()`|[Deprecated] Get hardcore and softcore completion metadata about games a user has played.|[docs](https://api-docs.retroachievements.org/v1/get-user-completed-games.html) \| [example](examples/user/getusercompletedgames/getusercompletedgames.go)|

<h3>Game</h3>

Expand Down
28 changes: 28 additions & 0 deletions examples/user/getusercompletedgames/getusercompletedgames.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Package getusercompletedgames provides an example for getting a users completed games
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 getusercompletedgames.go`
*/
func main() {
secret := os.Getenv("RA_API_KEY")

client := retroachievements.NewClient(secret)

resp, err := client.GetUserCompletedGames(models.GetUserCompletedGamesParameters{
Username: "jamiras",
})
if err != nil {
panic(err)
}

fmt.Printf("%+v\n", resp)
}
1 change: 0 additions & 1 deletion examples/user/getuserprogress/getuserprogress.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func main() {

resp, err := client.GetUserProgress(models.GetUserProgressParameters{
Username: "jamiras",
GameIDs: []int{1, 16247},
})
if err != nil {
panic(err)
Expand Down
17 changes: 17 additions & 0 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,20 @@ type GetUserSummaryLastGame struct {
Released LongMonthDate `json:"Released"`
IsFinal int `json:"IsFinal"`
}

type GetUserCompletedGamesParameters struct {
// The target username
Username string
}

type GetUserCompletedGames struct {
GameID int `json:"GameID"`
Title string `json:"Title"`
ImageIcon string `json:"ImageIcon"`
ConsoleID int `json:"ConsoleID"`
ConsoleName string `json:"ConsoleName"`
MaxPossible int `json:"MaxPossible"`
NumAwarded int `json:"NumAwarded"`
PctWon string `json:"PctWon"`
HardcoreMode string `json:"HardcoreMode"`
}
22 changes: 20 additions & 2 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (c *Client) GetUserPoints(params models.GetUserPointsParameters) (*models.G
}

// GetUserProgress get a user's progress on a list of specified games.
func (c *Client) GetUserProgress(params models.GetUserProgressParameters) (map[string]models.GetUserProgress, error) {
func (c *Client) GetUserProgress(params models.GetUserProgressParameters) (*map[string]models.GetUserProgress, error) {
resp, err := c.do(
raHttp.Method(http.MethodGet),
raHttp.Path("/API/API_GetUserProgress.php"),
Expand All @@ -217,7 +217,7 @@ func (c *Client) GetUserProgress(params models.GetUserProgressParameters) (map[s
if err != nil {
return nil, fmt.Errorf("parsing response object: %w", err)
}
return *progress, nil
return progress, nil
}

// GetUserRecentlyPlayedGames get a list of games a user has recently played.
Expand Down Expand Up @@ -269,3 +269,21 @@ func (c *Client) GetUserSummary(params models.GetUserSummaryParameters) (*models
}
return recentlyPlayed, nil
}

// GetUserCompletedGames gets completion metadata about the games a given user has played.
func (c *Client) GetUserCompletedGames(params models.GetUserCompletedGamesParameters) ([]models.GetUserCompletedGames, error) {
resp, err := c.do(
raHttp.Method(http.MethodGet),
raHttp.Path("/API/API_GetUserCompletedGames.php"),
raHttp.APIToken(c.Secret),
raHttp.Username(params.Username),
)
if err != nil {
return nil, fmt.Errorf("calling endpoint: %w", err)
}
games, err := raHttp.ResponseList[models.GetUserCompletedGames](resp)
if err != nil {
return nil, fmt.Errorf("parsing response list: %w", err)
}
return games, nil
}
145 changes: 138 additions & 7 deletions user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ func TestGetUserProgress(tt *testing.T) {
responseMessage map[string]models.GetUserProgress
responseError models.ErrorResponse
response func(messageBytes []byte, errorBytes []byte) []byte
assert func(t *testing.T, progress map[string]models.GetUserProgress, err error)
assert func(t *testing.T, progress *map[string]models.GetUserProgress, err error)
}{
{
name: "fail to call endpoint",
Expand All @@ -1607,7 +1607,7 @@ func TestGetUserProgress(tt *testing.T) {
response: func(messageBytes []byte, errorBytes []byte) []byte {
return errorBytes
},
assert: func(t *testing.T, resp map[string]models.GetUserProgress, err error) {
assert: func(t *testing.T, resp *map[string]models.GetUserProgress, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetUserProgress.php?i=1%2C2%2C5352&u=Test&y=some_secret\": unsupported protocol scheme \"\"")
},
Expand Down Expand Up @@ -1635,7 +1635,7 @@ func TestGetUserProgress(tt *testing.T) {
response: func(messageBytes []byte, errorBytes []byte) []byte {
return errorBytes
},
assert: func(t *testing.T, resp map[string]models.GetUserProgress, err error) {
assert: func(t *testing.T, resp *map[string]models.GetUserProgress, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "parsing response object: error responses: [401] Not Authorized")
},
Expand Down Expand Up @@ -1679,10 +1679,11 @@ func TestGetUserProgress(tt *testing.T) {
response: func(messageBytes []byte, errorBytes []byte) []byte {
return messageBytes
},
assert: func(t *testing.T, resp map[string]models.GetUserProgress, err error) {
assert: func(t *testing.T, resp *map[string]models.GetUserProgress, err error) {
require.NotNil(t, resp)
r := *resp
// first element
first, ok := resp["1"]
first, ok := r["1"]
require.True(t, ok)
require.Equal(t, 36, first.NumPossibleAchievements)
require.Equal(t, 305, first.PossibleScore)
Expand All @@ -1692,7 +1693,7 @@ func TestGetUserProgress(tt *testing.T) {
require.Equal(t, 100, first.ScoreAchievedHardcore)

// second element
second, ok := resp["2"]
second, ok := r["2"]
require.True(t, ok)
require.Equal(t, 56, second.NumPossibleAchievements)
require.Equal(t, 600, second.PossibleScore)
Expand All @@ -1702,7 +1703,7 @@ func TestGetUserProgress(tt *testing.T) {
require.Equal(t, 0, second.ScoreAchievedHardcore)

// third element
third, ok := resp["5352"]
third, ok := r["5352"]
require.True(t, ok)
require.Equal(t, 13, third.NumPossibleAchievements)
require.Equal(t, 230, third.PossibleScore)
Expand Down Expand Up @@ -2220,3 +2221,133 @@ func TestGetUserSummary(tt *testing.T) {
})
}
}

func TestGetUserCompletedGames(tt *testing.T) {
tests := []struct {
name string
params models.GetUserCompletedGamesParameters
modifyURL func(url string) string
responseCode int
responseMessage []models.GetUserCompletedGames
responseError models.ErrorResponse
response func(messageBytes []byte, errorBytes []byte) []byte
assert func(t *testing.T, resp []models.GetUserCompletedGames, err error)
}{
{
name: "fail to call endpoint",
params: models.GetUserCompletedGamesParameters{
Username: "Test",
},
modifyURL: func(url string) string {
return ""
},
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.GetUserCompletedGames, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetUserCompletedGames.php?u=Test&y=some_secret\": unsupported protocol scheme \"\"")
},
},
{
name: "error response",
params: models.GetUserCompletedGamesParameters{
Username: "Test",
},
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.GetUserCompletedGames, err error) {
require.Nil(t, resp)
require.EqualError(t, err, "parsing response list: error responses: [401] Not Authorized")
},
},
{
name: "success",
params: models.GetUserCompletedGamesParameters{
Username: "Test",
},
modifyURL: func(url string) string {
return url
},
responseCode: http.StatusOK,
responseMessage: []models.GetUserCompletedGames{
{
GameID: 24941,
Title: "Dragon Quest IV: Chapters of the Chosen [Subset - Plentiful Plunder]",
ImageIcon: "/Images/075762.png",
ConsoleID: 18,
ConsoleName: "Nintendo DS",
MaxPossible: 202,
NumAwarded: 202,
PctWon: "1.0000",
HardcoreMode: "1",
},
},
response: func(messageBytes []byte, errorBytes []byte) []byte {
return messageBytes
},
assert: func(t *testing.T, resp []models.GetUserCompletedGames, err error) {
require.NoError(t, err)
require.Len(t, resp, 1)
require.Equal(t, 24941, resp[0].GameID)
require.Equal(t, "Dragon Quest IV: Chapters of the Chosen [Subset - Plentiful Plunder]", resp[0].Title)
require.Equal(t, "/Images/075762.png", resp[0].ImageIcon)
require.Equal(t, 18, resp[0].ConsoleID)
require.Equal(t, "Nintendo DS", resp[0].ConsoleName)
require.Equal(t, 202, resp[0].MaxPossible)
require.Equal(t, 202, resp[0].NumAwarded)
require.Equal(t, "1.0000", resp[0].PctWon)
require.Equal(t, "1", resp[0].HardcoreMode)
},
},
}
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_GetUserCompletedGames.php"
if r.URL.Path != expectedPath {
t.Errorf("Expected to request '%s', got: %s", expectedPath, r.URL.Path)
}
w.WriteHeader(test.responseCode)
responseMessage, err := json.Marshal(test.responseMessage)
require.NoError(t, err)
errBytes, err := json.Marshal(test.responseError)
require.NoError(t, err)
resp := test.response(responseMessage, 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), "some_secret")
resp, err := client.GetUserCompletedGames(test.params)
test.assert(t, resp, err)
})
}
}

0 comments on commit b3c0762

Please sign in to comment.