From c42612c8f2124ad0fecd39511758113ed3ba2ab8 Mon Sep 17 00:00:00 2001 From: Joshua Raphael Date: Sun, 24 Nov 2024 10:56:41 -0700 Subject: [PATCH] add GetTicketByID endpoint --- README.md | 8 +- .../ticket/getticketbyid/getticketbyid.go | 28 +++ models/ticket.go | 32 ++++ ticket.go | 30 ++++ ticket_test.go | 168 ++++++++++++++++++ 5 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 examples/ticket/getticketbyid/getticketbyid.go create mode 100644 models/ticket.go create mode 100644 ticket.go create mode 100644 ticket_test.go diff --git a/README.md b/README.md index 6a890b2..b42279f 100644 --- a/README.md +++ b/README.md @@ -115,4 +115,10 @@ For convenience, the API docs and examples can be found in the tables below |Function|Description|Links| |-|-|-| -|`GetAchievementOfTheWeek()`|Gets comprehensive metadata about the current Achievement of the Week.|[docs](https://api-docs.retroachievements.org/v1/get-achievement-of-the-week.html) \| [example](examples/event/getachievementoftheweek/getachievementoftheweek.go)| \ No newline at end of file +|`GetAchievementOfTheWeek()`|Gets comprehensive metadata about the current Achievement of the Week.|[docs](https://api-docs.retroachievements.org/v1/get-achievement-of-the-week.html) \| [example](examples/event/getachievementoftheweek/getachievementoftheweek.go)| + +

Ticket

+ +|Function|Description|Links| +|-|-|-| +|`GetTicketByID()`|Gets ticket metadata information about a single achievement ticket, targeted by its ticket ID.|[docs](https://api-docs.retroachievements.org/v1/get-ticket-data/get-ticket-by-id.html) \| [example](examples/ticket/getticketbyid/getticketbyid.go)| \ No newline at end of file diff --git a/examples/ticket/getticketbyid/getticketbyid.go b/examples/ticket/getticketbyid/getticketbyid.go new file mode 100644 index 0000000..7b68bc6 --- /dev/null +++ b/examples/ticket/getticketbyid/getticketbyid.go @@ -0,0 +1,28 @@ +// Package getticketbyid provides an example for getting ticket metadata information about a single achievement ticket, targeted by its ticket ID. +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 getticketbyid.go` +*/ +func main() { + secret := os.Getenv("RA_API_KEY") + + client := retroachievements.NewClient(secret) + + resp, err := client.GetTicketByID(models.GetTicketByIDParameters{ + TicketID: 1, + }) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", resp) +} diff --git a/models/ticket.go b/models/ticket.go new file mode 100644 index 0000000..521de53 --- /dev/null +++ b/models/ticket.go @@ -0,0 +1,32 @@ +package models + +type GetTicketByIDParameters struct { + // The target ticket ID + TicketID int +} + +type GetTicketByID struct { + ID int `json:"ID"` + AchievementID int `json:"AchievementID"` + AchievementTitle string `json:"AchievementTitle"` + AchievementDesc string `json:"AchievementDesc"` + AchievementType *string `json:"AchievementType"` + Points int `json:"Points"` + BadgeName string `json:"BadgeName"` + AchievementAuthor string `json:"AchievementAuthor"` + GameID int `json:"GameID"` + ConsoleName string `json:"ConsoleName"` + GameTitle string `json:"GameTitle"` + GameIcon string `json:"GameIcon"` + ReportedAt DateTime `json:"ReportedAt"` + ReportType int `json:"ReportType"` + ReportState int `json:"ReportState"` + Hardcore *int `json:"Hardcore"` + ReportNotes string `json:"ReportNotes"` + ReportedBy string `json:"ReportedBy"` + ResolvedAt *DateTime `json:"ResolvedAt"` + ResolvedBy *string `json:"ResolvedBy"` + ReportStateDescription string `json:"ReportStateDescription"` + ReportTypeDescription string `json:"ReportTypeDescription"` + URL string `json:"URL"` +} diff --git a/ticket.go b/ticket.go new file mode 100644 index 0000000..84200ac --- /dev/null +++ b/ticket.go @@ -0,0 +1,30 @@ +package retroachievements + +import ( + "fmt" + "net/http" + "strconv" + + raHttp "github.com/joshraphael/go-retroachievements/http" + "github.com/joshraphael/go-retroachievements/models" +) + +// GetTicketByID gets ticket metadata information about a single achievement ticket, targeted by its ticket ID. +func (c *Client) GetTicketByID(params models.GetTicketByIDParameters) (*models.GetTicketByID, error) { + r, err := c.do( + raHttp.Method(http.MethodGet), + raHttp.Path("/API/API_GetTicketData.php"), + raHttp.APIToken(c.Secret), + raHttp.I([]string{ + strconv.Itoa(params.TicketID), + }), + ) + if err != nil { + return nil, fmt.Errorf("calling endpoint: %w", err) + } + resp, err := raHttp.ResponseObject[models.GetTicketByID](r) + if err != nil { + return nil, fmt.Errorf("parsing response object: %w", err) + } + return resp, nil +} diff --git a/ticket_test.go b/ticket_test.go new file mode 100644 index 0000000..dd7cc6b --- /dev/null +++ b/ticket_test.go @@ -0,0 +1,168 @@ +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 TestGetTicketByID(tt *testing.T) { + achievementType := "progression" + reportedAt, err := time.Parse(time.DateTime, "2014-02-22 23:23:53") + require.NoError(tt, err) + hardcore := 1 + resolvedAt, err := time.Parse(time.DateTime, "2014-02-24 22:51:10") + require.NoError(tt, err) + resolvedBy := "Scott" + tests := []struct { + name string + params models.GetTicketByIDParameters + modifyURL func(url string) string + responseCode int + responseMessage models.GetTicketByID + responseError models.ErrorResponse + response func(messageBytes []byte, errorBytes []byte) []byte + assert func(t *testing.T, resp *models.GetTicketByID, err error) + }{ + { + name: "fail to call endpoint", + params: models.GetTicketByIDParameters{ + TicketID: 1, + }, + 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.GetTicketByID, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "calling endpoint: Get \"/API/API_GetTicketData.php?i=1&y=some_secret\": unsupported protocol scheme \"\"") + }, + }, + { + name: "error response", + params: models.GetTicketByIDParameters{ + TicketID: 1, + }, + 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.GetTicketByID, err error) { + require.Nil(t, resp) + require.EqualError(t, err, "parsing response object: error code 401 returned: {\"message\":\"test\",\"errors\":[{\"status\":401,\"code\":\"unauthorized\",\"title\":\"Not Authorized\"}]}") + }, + }, + { + name: "success", + params: models.GetTicketByIDParameters{ + TicketID: 1, + }, + modifyURL: func(url string) string { + return url + }, + responseCode: http.StatusOK, + responseMessage: models.GetTicketByID{ + ID: 1, + AchievementID: 3778, + AchievementTitle: "Exhibition Match", + AchievementDesc: "Complete Stage 3: Flugelheim Museum", + AchievementType: &achievementType, + Points: 10, + BadgeName: "04357", + AchievementAuthor: "Batman", + GameID: 45, + ConsoleName: "Genesis/Mega Drive", + GameTitle: "Batman: The Video Game", + GameIcon: "/Images/053393.png", + ReportedAt: models.DateTime{ + Time: reportedAt, + }, + ReportType: 0, + ReportState: 2, + Hardcore: &hardcore, + ReportNotes: "This achievement didn't trigger for some reason?", + ReportedBy: "qwe", + ResolvedAt: &models.DateTime{ + Time: resolvedAt, + }, + ResolvedBy: &resolvedBy, + ReportStateDescription: "Resolved", + ReportTypeDescription: "Invalid ticket type", + URL: "https://retroachievements.org/ticket/1", + }, + response: func(messageBytes []byte, errorBytes []byte) []byte { + return messageBytes + }, + assert: func(t *testing.T, resp *models.GetTicketByID, err error) { + require.NotNil(t, resp) + require.Equal(t, 1, resp.ID) + require.Equal(t, 3778, resp.AchievementID) + require.Equal(t, "Exhibition Match", resp.AchievementTitle) + require.Equal(t, "Complete Stage 3: Flugelheim Museum", resp.AchievementDesc) + require.NotNil(t, resp.AchievementType) + require.Equal(t, achievementType, *resp.AchievementType) + require.Equal(t, 10, resp.Points) + require.Equal(t, "04357", resp.BadgeName) + require.Equal(t, "Batman", resp.AchievementAuthor) + require.Equal(t, 45, resp.GameID) + require.Equal(t, "Genesis/Mega Drive", resp.ConsoleName) + require.Equal(t, "Batman: The Video Game", resp.GameTitle) + require.Equal(t, "/Images/053393.png", resp.GameIcon) + require.Equal(t, reportedAt, resp.ReportedAt.Time) + require.Equal(t, 0, resp.ReportType) + require.Equal(t, 2, resp.ReportState) + require.NotNil(t, resp.ResolvedBy) + require.Equal(t, resolvedBy, *resp.ResolvedBy) + require.Equal(t, "Resolved", resp.ReportStateDescription) + require.Equal(t, "Invalid ticket type", resp.ReportTypeDescription) + require.Equal(t, "https://retroachievements.org/ticket/1", resp.URL) + 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_GetTicketData.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.GetTicketByID(test.params) + test.assert(t, resp, err) + }) + } +}