Skip to content

Commit

Permalink
add GetAchievementsEarnedBetween endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
joshraphael committed Aug 13, 2024
1 parent af87a67 commit bf22083
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 0 deletions.
24 changes: 24 additions & 0 deletions client/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package client
import (
"fmt"
"net/http"
"time"

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

// GetUserProfile gets the profile of a given username
func (c *Client) GetUserProfile(username string) (*models.Profile, error) {
resp, err := c.do(
raHttp.Method(http.MethodGet),
Expand All @@ -26,6 +28,7 @@ func (c *Client) GetUserProfile(username string) (*models.Profile, error) {
return profile, nil
}

// GetUserRecentAchievements gets all achievements within the last specified amount of minutes for a given username
func (c *Client) GetUserRecentAchievements(username string, lookbackMinutes int) ([]models.Achievement, error) {
resp, err := c.do(
raHttp.Method(http.MethodGet),
Expand All @@ -44,3 +47,24 @@ func (c *Client) GetUserRecentAchievements(username string, lookbackMinutes int)
}
return achievements, nil
}

// GetAchievementsEarnedBetween gets all achievements earned within a time frame for a given username
func (c *Client) GetAchievementsEarnedBetween(username string, from time.Time, to time.Time) ([]models.Achievement, error) {
resp, err := c.do(
raHttp.Method(http.MethodGet),
raHttp.Path("/API/API_GetAchievementsEarnedBetween.php"),
raHttp.APIToken(c.secret),
raHttp.Username(username),
raHttp.FromTime(from),
raHttp.ToTime(to),
)
if err != nil {
return nil, fmt.Errorf("calling endpoint: %w", err)
}
defer resp.Body.Close()
achievements, err := raHttp.ResponseList[models.Achievement](resp)
if err != nil {
return nil, fmt.Errorf("parsing response list: %w", err)
}
return achievements, nil
}
121 changes: 121 additions & 0 deletions client/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,124 @@ func TestGetUserRecentAchievements(tt *testing.T) {
})
}
}

func TestGetAchievementsEarnedBetween(tt *testing.T) {
now, err := time.Parse(time.DateTime, "2024-03-02 17:27:03")
require.NoError(tt, err)
later := now.Add(10 * time.Minute)
tests := []struct {
name string
username string
fromTime time.Time
toTime time.Time
responseCode int
responseAchievements []models.Achievement
responseError models.ErrorResponse
response func(achievementsBytes []byte, errorBytes []byte) []byte
assert func(t *testing.T, achievements []models.Achievement, err error)
}{
{
name: "error response",
username: "Test",
fromTime: now,
toTime: later,
responseCode: http.StatusUnauthorized,
responseError: models.ErrorResponse{
Message: "test",
Errors: []models.ErrorDetail{
{
Status: http.StatusUnauthorized,
Code: "unauthorized",
Title: "Not Authorized",
},
},
},
response: func(achievementsBytes []byte, errorBytes []byte) []byte {
return errorBytes
},
assert: func(t *testing.T, achievements []models.Achievement, err error) {
require.Nil(t, achievements)
require.EqualError(t, err, "parsing response list: error responses: [401] Not Authorized")
},
},
{
name: "error response",
username: "Test",
fromTime: now,
toTime: later,
responseCode: http.StatusOK,
responseAchievements: []models.Achievement{
{
Date: models.DateTime{
Time: now,
},
HardcoreMode: 1,
AchievementID: 34425,
Title: "Beat Level 1",
Description: "Finish level 1",
BadgeName: "840124",
Points: 10,
TrueRatio: 234,
Type: "win_condition",
Author: "jamiras",
GameTitle: "Final Fantasy XXXXIIII",
GameIcon: "/Images/056340.png",
GameID: 34897,
ConsoleName: "SNES",
BadgeURL: "/Badge/840124.png",
GameURL: "/game/34897",
},
},
response: func(achievementsBytes []byte, errorBytes []byte) []byte {
return achievementsBytes
},
assert: func(t *testing.T, achievements []models.Achievement, err error) {
require.NotNil(t, achievements)
require.Len(t, achievements, 1)
require.Equal(t, models.DateTime{
Time: now,
}, achievements[0].Date)
require.Equal(t, 1, achievements[0].HardcoreMode)
require.Equal(t, 34425, achievements[0].AchievementID)
require.Equal(t, "Beat Level 1", achievements[0].Title)
require.Equal(t, "Finish level 1", achievements[0].Description)
require.Equal(t, "840124", achievements[0].BadgeName)
require.Equal(t, 10, achievements[0].Points)
require.Equal(t, 234, achievements[0].TrueRatio)
require.Equal(t, "win_condition", achievements[0].Type)
require.Equal(t, "jamiras", achievements[0].Author)
require.Equal(t, "Final Fantasy XXXXIIII", achievements[0].GameTitle)
require.Equal(t, "/Images/056340.png", achievements[0].GameIcon)
require.Equal(t, 34897, achievements[0].GameID)
require.Equal(t, "SNES", achievements[0].ConsoleName)
require.Equal(t, "/Badge/840124.png", achievements[0].BadgeURL)
require.Equal(t, "/game/34897", achievements[0].GameURL)
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_GetAchievementsEarnedBetween.php"
if r.URL.Path != expectedPath {
t.Errorf("Expected to request '%s', got: %s", expectedPath, r.URL.Path)
}
w.WriteHeader(test.responseCode)
achievementsBytes, err := json.Marshal(test.responseAchievements)
require.NoError(t, err)
errBytes, err := json.Marshal(test.responseError)
require.NoError(t, err)
resp := test.response(achievementsBytes, errBytes)
num, err := w.Write(resp)
require.NoError(t, err)
require.Equal(t, num, len(resp))
}))
defer server.Close()

client := client.New(server.URL, "some_secret")
achievements, err := client.GetAchievementsEarnedBetween(test.username, test.fromTime, test.toTime)
test.assert(t, achievements, err)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Package getachievementsearnedbetween provides an example for a users achievements between two timestamps
package main

import (
"fmt"
"os"
"time"

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

/*
Test script for getting user profile. Add RA_API_KEY to your env and use `go run getachievementsearnedbetween.go`
*/
func main() {
host := "https://retroachievements.org"
secret := os.Getenv("RA_API_KEY")

raClient := client.New(host, secret)

now, err := time.Parse(time.DateTime, "2024-03-02 17:27:03")
if err != nil {
panic(err)
}
later := now.Add(10 * time.Minute)

resp, err := raClient.GetAchievementsEarnedBetween("jamiras", now, later)
if err != nil {
panic(err)
}

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

// Request holds values for an http call
Expand Down Expand Up @@ -65,6 +66,20 @@ func LookbackMinutes(minutes int) RequestDetail {
})
}

// FromTime adds a start time to the query parameters in unix seconds
func FromTime(t time.Time) RequestDetail {
return requestDetailFn(func(r *Request) {
r.Params["f"] = strconv.Itoa(int(t.Unix()))
})
}

// ToTime adds a end time to the query parameters in unix seconds
func ToTime(t time.Time) RequestDetail {
return requestDetailFn(func(r *Request) {
r.Params["t"] = strconv.Itoa(int(t.Unix()))
})
}

// Path adds a URL path to the host
func Path(path string) RequestDetail {
return requestDetailFn(func(r *Request) {
Expand Down
8 changes: 8 additions & 0 deletions http/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package http_test
import (
"net/http"
"testing"
"time"

raHttp "github.com/joshraphael/go-retroachievements/http"
"github.com/stretchr/testify/require"
)

func TestNewRequest(t *testing.T) {
now, err := time.Parse(time.DateTime, "2024-03-02 17:27:03")
require.NoError(t, err)
later := now.Add(10 * time.Minute)
actual := raHttp.NewRequest(
"http://localhost",
raHttp.Path("/api/v1/some_resource"),
Expand All @@ -17,6 +21,8 @@ func TestNewRequest(t *testing.T) {
raHttp.BearerToken("secret_bearer"),
raHttp.Username("myUsername"),
raHttp.LookbackMinutes(10),
raHttp.FromTime(now),
raHttp.ToTime(later),
)

expected := &raHttp.Request{
Expand All @@ -30,6 +36,8 @@ func TestNewRequest(t *testing.T) {
"y": "secret_token",
"m": "10",
"u": "myUsername",
"f": "1709400423",
"t": "1709401023",
},
}

Expand Down

0 comments on commit bf22083

Please sign in to comment.