-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
707e8e7
commit fcc6efc
Showing
6 changed files
with
309 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package retroachievements | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
|
||
raHttp "github.com/joshraphael/go-retroachievements/http" | ||
"github.com/joshraphael/go-retroachievements/models" | ||
) | ||
|
||
// GetAchievementUnlocks gets a list of users who have earned an achievement. | ||
func (c *Client) GetAchievementUnlocks(params models.GetAchievementUnlocksParameters) (*models.GetAchievementUnlocks, error) { | ||
details := []raHttp.RequestDetail{ | ||
raHttp.Method(http.MethodGet), | ||
raHttp.Path("/API/API_GetAchievementUnlocks.php"), | ||
raHttp.APIToken(c.Secret), | ||
raHttp.A(params.AchievementID), | ||
} | ||
if params.Count != nil { | ||
details = append(details, raHttp.C(*params.Count)) | ||
} | ||
if params.Offset != nil { | ||
details = append(details, raHttp.O(*params.Offset)) | ||
} | ||
r, err := c.do(details...) | ||
if err != nil { | ||
return nil, fmt.Errorf("calling endpoint: %w", err) | ||
} | ||
resp, err := raHttp.ResponseObject[models.GetAchievementUnlocks](r) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing response object: %w", err) | ||
} | ||
return resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package retroachievements_test | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
|
||
"github.com/joshraphael/go-retroachievements" | ||
"github.com/joshraphael/go-retroachievements/models" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGetAchievementUnlocks(tt *testing.T) { | ||
count := 10 | ||
offset := 10 | ||
achievementType := "progression" | ||
dateCreated, err := time.Parse(time.DateTime, "2012-11-02 00:03:12") | ||
require.NoError(tt, err) | ||
dateModified, err := time.Parse(time.DateTime, "2023-09-30 02:00:49") | ||
require.NoError(tt, err) | ||
dateAwarded, err := time.Parse(time.RFC3339Nano, "2024-11-22T17:25:17.000000Z") | ||
require.NoError(tt, err) | ||
tests := []struct { | ||
name string | ||
params models.GetAchievementUnlocksParameters | ||
modifyURL func(url string) string | ||
responseCode int | ||
responseMessage models.GetAchievementUnlocks | ||
responseError models.ErrorResponse | ||
response func(messageBytes []byte, errorBytes []byte) []byte | ||
assert func(t *testing.T, resp *models.GetAchievementUnlocks, err error) | ||
}{ | ||
{ | ||
name: "fail to call endpoint", | ||
params: models.GetAchievementUnlocksParameters{ | ||
AchievementID: 14402, | ||
Count: &count, | ||
Offset: &offset, | ||
}, | ||
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.GetAchievementUnlocks, err error) { | ||
require.Nil(t, resp) | ||
require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetAchievementUnlocks.php?a=14402&c=10&o=10&y=some_secret\": unsupported protocol scheme \"\"") | ||
}, | ||
}, | ||
{ | ||
name: "error response", | ||
params: models.GetAchievementUnlocksParameters{ | ||
AchievementID: 14402, | ||
Count: &count, | ||
Offset: &offset, | ||
}, | ||
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.GetAchievementUnlocks, err error) { | ||
require.Nil(t, resp) | ||
require.EqualError(t, err, "parsing response object: error responses: [401] Not Authorized") | ||
}, | ||
}, | ||
{ | ||
name: "success", | ||
params: models.GetAchievementUnlocksParameters{ | ||
AchievementID: 14402, | ||
Count: &count, | ||
Offset: &offset, | ||
}, | ||
modifyURL: func(url string) string { | ||
return url | ||
}, | ||
responseCode: http.StatusOK, | ||
responseMessage: models.GetAchievementUnlocks{ | ||
UnlocksCount: 15906, | ||
UnlocksHardcoreCount: 8223, | ||
TotalPlayers: 38104, | ||
Achievement: models.GetAchievementUnlocksAchievement{ | ||
ID: 1, | ||
Title: "Ring Collector", | ||
Description: "Collect 100 rings", | ||
Points: 5, | ||
TrueRatio: 7, | ||
Author: "Scott", | ||
DateCreated: models.DateTime{ | ||
Time: dateCreated, | ||
}, | ||
DateModified: models.DateTime{ | ||
Time: dateModified, | ||
}, | ||
Type: &achievementType, | ||
}, | ||
Console: models.GetAchievementUnlocksConsole{ | ||
ID: 1, | ||
Title: "Genesis/Mega Drive", | ||
}, | ||
Game: models.GetAchievementUnlocksGame{ | ||
ID: 1, | ||
Title: "Sonic the Hedgehog", | ||
}, | ||
Unlocks: []models.GetAchievementUnlocksUnlock{ | ||
{ | ||
User: "redjedia", | ||
RAPoints: 524, | ||
RASoftcorePoints: 1615, | ||
DateAwarded: dateAwarded, | ||
HardcoreMode: 0, | ||
}, | ||
}, | ||
}, | ||
response: func(messageBytes []byte, errorBytes []byte) []byte { | ||
return messageBytes | ||
}, | ||
assert: func(t *testing.T, resp *models.GetAchievementUnlocks, err error) { | ||
require.NotNil(t, resp) | ||
require.Equal(t, 15906, resp.UnlocksCount) | ||
require.Equal(t, 8223, resp.UnlocksHardcoreCount) | ||
require.Equal(t, 38104, resp.TotalPlayers) | ||
require.Equal(t, 1, resp.Achievement.ID) | ||
require.Equal(t, "Ring Collector", resp.Achievement.Title) | ||
require.Equal(t, "Collect 100 rings", resp.Achievement.Description) | ||
require.Equal(t, 5, resp.Achievement.Points) | ||
require.Equal(t, 7, resp.Achievement.TrueRatio) | ||
require.Equal(t, "Scott", resp.Achievement.Author) | ||
require.Equal(t, dateCreated, resp.Achievement.DateCreated.Time) | ||
require.Equal(t, dateModified, resp.Achievement.DateModified.Time) | ||
require.NotNil(t, resp.Achievement.Type) | ||
require.Equal(t, achievementType, *resp.Achievement.Type) | ||
require.Equal(t, 1, resp.Console.ID) | ||
require.Equal(t, "Genesis/Mega Drive", resp.Console.Title) | ||
require.Equal(t, 1, resp.Game.ID) | ||
require.Equal(t, "Sonic the Hedgehog", resp.Game.Title) | ||
require.Len(t, resp.Unlocks, 1) | ||
require.Equal(t, "redjedia", resp.Unlocks[0].User) | ||
require.Equal(t, 524, resp.Unlocks[0].RAPoints) | ||
require.Equal(t, 1615, resp.Unlocks[0].RASoftcorePoints) | ||
require.Equal(t, dateAwarded, resp.Unlocks[0].DateAwarded) | ||
require.Equal(t, 0, resp.Unlocks[0].HardcoreMode) | ||
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_GetAchievementUnlocks.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.GetAchievementUnlocks(test.params) | ||
test.assert(t, resp, err) | ||
}) | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
examples/achievement/getachievementunlocks/getachievementunlocks.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Package getachievementunlocks provides an example for getting a list of users who have earned an achievement | ||
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 getachievementunlocks.go` | ||
*/ | ||
func main() { | ||
secret := os.Getenv("RA_API_KEY") | ||
|
||
client := retroachievements.NewClient(secret) | ||
|
||
resp, err := client.GetAchievementUnlocks(models.GetAchievementUnlocksParameters{ | ||
AchievementID: 1, | ||
}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
fmt.Printf("%+v\n", resp) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package models | ||
|
||
import "time" | ||
|
||
type GetAchievementUnlocksParameters struct { | ||
// The target achievement ID | ||
AchievementID int | ||
|
||
// [Optional] The number of records to return (default: 50, max: 500). | ||
Count *int | ||
|
||
// [Optional] The number of entries to skip (default: 0). | ||
Offset *int | ||
} | ||
|
||
type GetAchievementUnlocks struct { | ||
Achievement GetAchievementUnlocksAchievement `json:"Achievement"` | ||
Console GetAchievementUnlocksConsole `json:"Console"` | ||
Game GetAchievementUnlocksGame `json:"Game"` | ||
UnlocksCount int `json:"UnlocksCount"` | ||
UnlocksHardcoreCount int `json:"UnlocksHardcoreCount"` | ||
TotalPlayers int `json:"TotalPlayers"` | ||
Unlocks []GetAchievementUnlocksUnlock `json:"Unlocks"` | ||
} | ||
|
||
type GetAchievementUnlocksAchievement struct { | ||
ID int `json:"ID"` | ||
Title string `json:"Title"` | ||
Description string `json:"Description"` | ||
Points int `json:"Points"` | ||
TrueRatio int `json:"TrueRatio"` | ||
Author string `json:"Author"` | ||
DateCreated DateTime `json:"DateCreated"` | ||
DateModified DateTime `json:"DateModified"` | ||
Type *string `json:"Type"` | ||
} | ||
|
||
type GetAchievementUnlocksConsole struct { | ||
ID int `json:"ID"` | ||
Title string `json:"Title"` | ||
} | ||
|
||
type GetAchievementUnlocksGame struct { | ||
ID int `json:"ID"` | ||
Title string `json:"Title"` | ||
} | ||
|
||
type GetAchievementUnlocksUnlock struct { | ||
User string `json:"User"` | ||
RAPoints int `json:"RAPoints"` | ||
RASoftcorePoints int `json:"RASoftcorePoints"` | ||
DateAwarded time.Time `json:"DateAwarded"` | ||
HardcoreMode int `json:"HardcoreMode"` | ||
} |