diff --git a/butlerd/generous/docs/README.md b/butlerd/generous/docs/README.md index 4f169836..bd450935 100644 --- a/butlerd/generous/docs/README.md +++ b/butlerd/generous/docs/README.md @@ -1948,6 +1948,86 @@ afterwards with ‘Fresh’ set

+### Fetch.UploadBuilds (client request) + + +

+

Fetches builds for an itch.io game

+ +

+ +

+Parameters +

+ + + + + + + + + + + + + +
gameGame

Game whose builds we should look for

+
uploadUpload

Upload whose builds we should look for

+
+ + + +

+Result +

+ + + + + + + + +
buildsBuild[]

List of builds

+
+ + +
+

Fetch.UploadBuilds (client request) (Go to definition)

+ +

+

Fetches builds for an itch.io game

+ +

+ + + + + + + + + + +
gameGame
uploadUpload
+ +
+ + +
+

FetchUploadBuilds (Go to definition)

+ + + + + + + +
buildsBuild[]
+ +
+ ### Fetch.User (client request) diff --git a/butlerd/generous/spec/butlerd.json b/butlerd/generous/spec/butlerd.json index 100ffc37..5ea46a42 100644 --- a/butlerd/generous/spec/butlerd.json +++ b/butlerd/generous/spec/butlerd.json @@ -616,6 +616,34 @@ ] } }, + { + "method": "Fetch.UploadBuilds", + "doc": "Fetches builds for an itch.io game", + "caller": "client", + "params": { + "fields": [ + { + "name": "game", + "doc": "Game whose builds we should look for", + "type": "Game" + }, + { + "name": "upload", + "doc": "Upload whose builds we should look for", + "type": "Upload" + } + ] + }, + "result": { + "fields": [ + { + "name": "builds", + "doc": "List of builds", + "type": "Build[]" + } + ] + } + }, { "method": "Fetch.User", "doc": "Fetches information for an itch.io user.", diff --git a/butlerd/messages/messages.go b/butlerd/messages/messages.go index 72f567d8..e061a464 100644 --- a/butlerd/messages/messages.go +++ b/butlerd/messages/messages.go @@ -1152,6 +1152,46 @@ func (r *FetchGameUploadsType) TestCall(rc *butlerd.RequestContext, params butle var FetchGameUploads *FetchGameUploadsType +// Fetch.UploadBuilds (Request) + +type FetchUploadBuildsType struct {} + +var _ RequestMessage = (*FetchUploadBuildsType)(nil) + +func (r *FetchUploadBuildsType) Method() string { + return "Fetch.UploadBuilds" +} + +func (r *FetchUploadBuildsType) Register(router router, f func(*butlerd.RequestContext, butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error)) { + router.Register("Fetch.UploadBuilds", func (rc *butlerd.RequestContext) (interface{}, error) { + var params butlerd.FetchUploadBuildsParams + err := json.Unmarshal(*rc.Params, ¶ms) + if err != nil { + return nil, &butlerd.RpcError{Code: jsonrpc2.CodeParseError, Message: err.Error()} + } + err = params.Validate() + if err != nil { + return nil, err + } + res, err := f(rc, params) + if err != nil { + return nil, err + } + if res == nil { + return nil, errors.New("internal error: nil result for Fetch.UploadBuilds") + } + return res, nil + }) +} + +func (r *FetchUploadBuildsType) TestCall(rc *butlerd.RequestContext, params butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error) { + var result butlerd.FetchUploadBuildsResult + err := rc.Call("Fetch.UploadBuilds", params, &result) + return &result, err +} + +var FetchUploadBuilds *FetchUploadBuildsType + // Fetch.User (Request) type FetchUserType struct {} @@ -3544,6 +3584,7 @@ func EnsureAllRequests(router *butlerd.Router) { if _, ok := router.Handlers["Fetch.DownloadKey"]; !ok { panic("missing request handler for (Fetch.DownloadKey)") } if _, ok := router.Handlers["Fetch.DownloadKeys"]; !ok { panic("missing request handler for (Fetch.DownloadKeys)") } if _, ok := router.Handlers["Fetch.GameUploads"]; !ok { panic("missing request handler for (Fetch.GameUploads)") } + if _, ok := router.Handlers["Fetch.UploadBuilds"]; !ok { panic("missing request handler for (Fetch.UploadBuilds)") } if _, ok := router.Handlers["Fetch.User"]; !ok { panic("missing request handler for (Fetch.User)") } if _, ok := router.Handlers["Fetch.Sale"]; !ok { panic("missing request handler for (Fetch.Sale)") } if _, ok := router.Handlers["Fetch.Collection"]; !ok { panic("missing request handler for (Fetch.Collection)") } diff --git a/butlerd/types.go b/butlerd/types.go index 134e463a..e36adbdd 100644 --- a/butlerd/types.go +++ b/butlerd/types.go @@ -715,6 +715,31 @@ func (r *FetchGameUploadsResult) SetStale(stale bool) { r.Stale = stale } +// Fetches builds for an itch.io game +// +// @name Fetch.UploadBuilds +// @category Fetch +// @caller client +type FetchUploadBuildsParams struct { + // Game whose builds we should look for + Game *itchio.Game `json:"game"` + + // Upload whose builds we should look for + Upload *itchio.Upload `json:"upload"` +} + +func (p FetchUploadBuildsParams) Validate() error { + return validation.ValidateStruct(&p, + validation.Field(&p.Game, validation.Required), + validation.Field(&p.Upload, validation.Required), + ) +} + +type FetchUploadBuildsResult struct { + // List of builds + Builds []*itchio.Build `json:"builds"` +} + // Fetches information for an itch.io user. // // @name Fetch.User diff --git a/endpoints/fetch/fetch.go b/endpoints/fetch/fetch.go index eda5ede6..ce70b8bb 100644 --- a/endpoints/fetch/fetch.go +++ b/endpoints/fetch/fetch.go @@ -8,6 +8,7 @@ import ( func Register(router *butlerd.Router) { messages.FetchGame.Register(router, FetchGame) messages.FetchGameUploads.Register(router, FetchGameUploads) + messages.FetchUploadBuilds.Register(router, FetchUploadBuilds) messages.FetchUser.Register(router, FetchUser) messages.FetchSale.Register(router, FetchSale) messages.FetchCollection.Register(router, FetchCollection) diff --git a/endpoints/fetch/fetch_upload_builds.go b/endpoints/fetch/fetch_upload_builds.go new file mode 100644 index 00000000..fb614f66 --- /dev/null +++ b/endpoints/fetch/fetch_upload_builds.go @@ -0,0 +1,31 @@ +package fetch + +import ( + "crawshaw.io/sqlite" + "github.com/itchio/butler/butlerd" + "github.com/itchio/butler/cmd/operate" + "github.com/itchio/go-itchio" + "github.com/pkg/errors" +) + +func FetchUploadBuilds(rc *butlerd.RequestContext, params butlerd.FetchUploadBuildsParams) (*butlerd.FetchUploadBuildsResult, error) { + res := &butlerd.FetchUploadBuildsResult{} + + var access *operate.GameAccess + rc.WithConn(func(conn *sqlite.Conn) { + access = operate.AccessForGameID(conn, params.Game.ID) + }) + client := rc.Client(access.APIKey) + + buildsRes, err := client.ListUploadBuilds(rc.Ctx, itchio.ListUploadBuildsParams{ + UploadID: params.Upload.ID, + Credentials: access.Credentials, + }) + if err != nil { + return nil, errors.WithStack(err) + } + + res.Builds = buildsRes.Builds + + return res, nil +}