summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDJ O'Leary <dijitol@proton.me>2026-09-07 03:13:01 +0200
committerDJ O'Leary <dijitol@proton.me>2026-09-07 03:13:01 +0200
commit2f61b07aea82fa0f5b98686bdfeba2e297c7b21b (patch)
treeb55f588e935b11decd782e7bd0a6c98f060e1654
parent5d3efcc64fc9664e061b44659f85aeec03a56685 (diff)
refactor(cardmarket): move handlers to own directoryHEADmain
-rw-r--r--main.go49
-rw-r--r--src/cardmarket/game.go24
-rw-r--r--src/cardmarket/handlers/account.go (renamed from src/cardmarket/account.go)12
-rw-r--r--src/cardmarket/handlers/game.go26
-rw-r--r--src/cardmarket/handlers/vacation.go47
-rw-r--r--src/cardmarket/http.go88
-rw-r--r--src/config/config.go12
-rw-r--r--src/oauth/client.go17
8 files changed, 230 insertions, 45 deletions
diff --git a/main.go b/main.go
index 68e4adf..4fb8231 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
+ "errors"
"flag"
"fmt"
"io"
@@ -10,6 +11,7 @@ import (
"os"
"codeberg.org/dijitol/trading_post/src/cardmarket"
+ "codeberg.org/dijitol/trading_post/src/cardmarket/handlers"
"codeberg.org/dijitol/trading_post/src/cli"
"codeberg.org/dijitol/trading_post/src/config"
"codeberg.org/dijitol/trading_post/src/oauth"
@@ -52,7 +54,7 @@ func Run(
"account",
"[account] outputs information about the owner of the credentials",
func(_ *flag.FlagSet) error {
- account, err := client.GetAccountInformation(ctx)
+ account, err := handlers.GetAccountInformation(ctx, client)
if err != nil {
return err
}
@@ -62,7 +64,34 @@ func Run(
return err
}
- fmt.Fprintln(stdout, string(out))
+ _, _ = fmt.Fprintln(stdout, string(out))
+
+ return nil
+ },
+ )
+ sg.AddSubcommand(
+ "vacation",
+ "[vacation] sets the vacation state",
+ func(fs *flag.FlagSet) error {
+ onVacation := fs.Bool("onVacation", false, "flag if the user is on vacation or not")
+ cancelOrders := fs.Bool("cancelOrders", false, "flag to cancel open orders, resp. request cancellation for open orders")
+ relistItems := fs.Bool("relistItems", false, "flag to relist items for cancelled orders; only applies if (cancelOrders) is also provided and set to true for all orders, that are effectively cancelled")
+
+ if err := fs.Parse(args[2:]); err != nil {
+ return err
+ }
+
+ if err := handlers.SetVacationState(
+ ctx,
+ client,
+ *onVacation,
+ cancelOrders,
+ relistItems,
+ ); err != nil {
+ return err
+ }
+
+ _, _ = fmt.Fprintln(stdout, "")
return nil
},
@@ -71,7 +100,7 @@ func Run(
"games",
"[games] outputs all the games",
func(_ *flag.FlagSet) error {
- games, err := client.GetGames(ctx)
+ games, err := handlers.GetGames(ctx, client)
if err != nil {
return err
}
@@ -81,18 +110,24 @@ func Run(
return err
}
- fmt.Fprintln(stdout, string(out))
+ _, _ = fmt.Fprintln(stdout, string(out))
return nil
},
)
if len(args) < 2 { // 1st if program name, 2nd is subcommand
- return fmt.Errorf("error: missing subcommand - usage: `trading_post [command]`\n%s", sg.Usage())
+ return fmt.Errorf("error: missing subcommand\n\nusage: `trading_post [subcommand]`\n%s", sg.Usage())
+ }
+
+ subcmd := args[1]
+
+ if subcmd == "--help" || subcmd == "-h" {
+ return fmt.Errorf("usage: `trading_post [subcommand]`\n%s", sg.Usage())
}
- if err := sg.ExecSubcommand(args[1]); err != nil {
- return err
+ if err := sg.ExecSubcommand(subcmd); err != nil {
+ return errors.Join(err, fmt.Errorf("\nusage: `trading_post [subcommand]`\n%s", sg.Usage()))
}
return nil
diff --git a/src/cardmarket/game.go b/src/cardmarket/game.go
deleted file mode 100644
index 995162d..0000000
--- a/src/cardmarket/game.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package cardmarket
-
-import (
- "context"
-)
-
-type Game struct {
- GameID uint32 `json:"idGame"`
- Name string `json:"name"`
- Abbreviation string `json:"abbreviation"`
- Links Links `json:"links"`
-}
-
-func (c *ApiClient) GetGames(ctx context.Context) ([]Game, error) {
- type responseBody struct {
- Game []Game `json:"game"`
- Links Links `json:"links"`
- }
- respBody := &responseBody{}
- if err := c.get(ctx, "/games", respBody); err != nil {
- return nil, err
- }
- return respBody.Game, nil
-}
diff --git a/src/cardmarket/account.go b/src/cardmarket/handlers/account.go
index bdef2bd..213766d 100644
--- a/src/cardmarket/account.go
+++ b/src/cardmarket/handlers/account.go
@@ -1,7 +1,9 @@
-package cardmarket
+package handlers
import (
"context"
+
+ "codeberg.org/dijitol/trading_post/src/cardmarket"
)
type Account struct {
@@ -57,13 +59,13 @@ type Account struct {
LossPercentage string `json:"lossPercentage"`
}
-func (c *ApiClient) GetAccountInformation(ctx context.Context) (Account, error) {
+func GetAccountInformation(ctx context.Context, c *cardmarket.ApiClient) (Account, error) {
type responseBody struct {
- Account Account `json:"account"`
- Links Links `json:"links"`
+ Account Account `json:"account"`
+ Links cardmarket.Links `json:"links"`
}
respBody := &responseBody{}
- if err := c.get(ctx, "/account", respBody); err != nil {
+ if err := c.Get(ctx, "/account", nil, respBody); err != nil {
return Account{}, err
}
return respBody.Account, nil
diff --git a/src/cardmarket/handlers/game.go b/src/cardmarket/handlers/game.go
new file mode 100644
index 0000000..99b9046
--- /dev/null
+++ b/src/cardmarket/handlers/game.go
@@ -0,0 +1,26 @@
+package handlers
+
+import (
+ "context"
+
+ "codeberg.org/dijitol/trading_post/src/cardmarket"
+)
+
+type Game struct {
+ GameID uint32 `json:"idGame"`
+ Name string `json:"name"`
+ Abbreviation string `json:"abbreviation"`
+ Links cardmarket.Links `json:"links"`
+}
+
+func GetGames(ctx context.Context, c *cardmarket.ApiClient) ([]Game, error) {
+ type responseBody struct {
+ Game []Game `json:"game"`
+ Links cardmarket.Links `json:"links"`
+ }
+ respBody := &responseBody{}
+ if err := c.Get(ctx, "/games", nil, respBody); err != nil {
+ return nil, err
+ }
+ return respBody.Game, nil
+}
diff --git a/src/cardmarket/handlers/vacation.go b/src/cardmarket/handlers/vacation.go
new file mode 100644
index 0000000..59528ed
--- /dev/null
+++ b/src/cardmarket/handlers/vacation.go
@@ -0,0 +1,47 @@
+package handlers
+
+import (
+ "context"
+
+ "codeberg.org/dijitol/trading_post/src/cardmarket"
+)
+
+func SetVacationState(
+ ctx context.Context,
+ c *cardmarket.ApiClient,
+ onVacation bool,
+ cancelOrders, relistItems *bool,
+) error {
+ params := make(map[string]string, 3)
+
+ if onVacation {
+ params["onVacation"] = "true"
+ } else {
+ params["onVacation"] = "false"
+ }
+
+ if cancelOrders != nil {
+ if *cancelOrders {
+ params["cancelOrders"] = "true"
+ if relistItems != nil && *relistItems {
+ params["relistItems"] = "true"
+ }
+ } else {
+ params["cancelOrders"] = "false"
+ params["relistItems"] = "false"
+ }
+ }
+
+ if err := c.Put(
+ ctx,
+ "/account/vacation",
+ params,
+ "",
+ nil,
+ nil,
+ ); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/src/cardmarket/http.go b/src/cardmarket/http.go
index 4789fdf..010f884 100644
--- a/src/cardmarket/http.go
+++ b/src/cardmarket/http.go
@@ -3,13 +3,85 @@ package cardmarket
import (
"context"
"encoding/json"
+ "errors"
"io"
"log/slog"
+ "strings"
)
-func (c *ApiClient) get(ctx context.Context, endpoint string, respBody any) error {
+func (c *ApiClient) Get(
+ ctx context.Context,
+ endpoint string,
+ params map[string]string,
+ respBody any,
+) error {
+ url := c.baseURL + endpoint
+
+ slog.DebugContext(ctx, "building query param string...")
+ parts := make([]string, len(params))
+ i := 0
+ for k, v := range params {
+ parts[i] = k + "=" + v
+ i++
+ }
+ query := strings.Join(parts, "&")
+ if query != "" {
+ url += "?" + query
+ }
+ slog.DebugContext(ctx, "built query param string")
+
+ slog.DebugContext(ctx, "requesting entity info...")
+ resp, err := c.httpClient.GetWithContext(ctx, url)
+ if err != nil {
+ slog.DebugContext(ctx, "failed to get entity from API")
+ return err
+ }
+ slog.DebugContext(ctx, "received entity info")
+
+ slog.DebugContext(ctx, "reading body...")
+ respBodyBuf, err := io.ReadAll(resp.Body)
+ if err != nil {
+ slog.DebugContext(ctx, "failed to read body")
+ return err
+ }
+ defer resp.Body.Close()
+ slog.DebugContext(ctx, "read body")
+
+ slog.DebugContext(ctx, "parsing body...", "respBodyBuf", string(respBodyBuf))
+ if err = json.Unmarshal(respBodyBuf, respBody); err != nil {
+ slog.DebugContext(ctx, "failed to unmarshal body: "+string(respBodyBuf))
+ return err
+ }
+ slog.DebugContext(ctx, "parsed body")
+
+ return nil
+}
+
+func (c *ApiClient) Put(
+ ctx context.Context,
+ endpoint string,
+ params map[string]string,
+ contentType string,
+ reqBody io.Reader,
+ respBody any,
+) error {
+ url := c.baseURL + endpoint
+
+ slog.DebugContext(ctx, "building query param string...")
+ parts := make([]string, len(params))
+ i := 0
+ for k, v := range params {
+ parts[i] = k + "=" + v
+ i++
+ }
+ query := strings.Join(parts, "&")
+ if query != "" {
+ url += "?" + query
+ }
+ slog.DebugContext(ctx, "built query param string")
+
slog.DebugContext(ctx, "requesting entity info...")
- resp, err := c.httpClient.GetWithContext(ctx, c.baseURL+endpoint)
+ resp, err := c.httpClient.PutWithContext(ctx, url, contentType, reqBody)
if err != nil {
slog.DebugContext(ctx, "failed to get entity from API")
return err
@@ -25,6 +97,18 @@ func (c *ApiClient) get(ctx context.Context, endpoint string, respBody any) erro
defer resp.Body.Close()
slog.DebugContext(ctx, "read body")
+ if resp.StatusCode < 200 || resp.StatusCode > 299 {
+ msg := "status code outside of successful range - " + resp.Status
+ if len(respBodyBuf) > 0 {
+ msg += " body=" + string(respBodyBuf)
+ }
+ return errors.New(msg)
+ }
+
+ if respBody == nil {
+ return nil
+ }
+
slog.DebugContext(ctx, "parsing body...", "respBodyBuf", string(respBodyBuf))
if err = json.Unmarshal(respBodyBuf, respBody); err != nil {
slog.DebugContext(ctx, "failed to unmarshal body: "+string(respBodyBuf))
diff --git a/src/config/config.go b/src/config/config.go
index 664bef3..fc5d71a 100644
--- a/src/config/config.go
+++ b/src/config/config.go
@@ -18,11 +18,11 @@ const (
)
var (
- ErrMissingCardmarketAppToken = errors.New("err: missing " + CardmarketAppToken + " in ENV")
- ErrMissingCardmarketAppSecret = errors.New("err: missing " + CardmarketAppSecret + " in ENV")
- ErrMissingCardmarketAccessToken = errors.New("err: missing " + CardmarketAccessToken + " in ENV")
- ErrMissingCardmarketAccessTokenSecret = errors.New("err: missing " + CardmarketAccessTokenSecret + " in ENV")
- ErrMissingCardmarketApiBaseURL = errors.New("err: missing " + CardmarketApiBaseURL + " in ENV")
+ ErrMissingCardmarketAppToken = errors.New("error: missing " + CardmarketAppToken + " in ENV")
+ ErrMissingCardmarketAppSecret = errors.New("error: missing " + CardmarketAppSecret + " in ENV")
+ ErrMissingCardmarketAccessToken = errors.New("error: missing " + CardmarketAccessToken + " in ENV")
+ ErrMissingCardmarketAccessTokenSecret = errors.New("error: missing " + CardmarketAccessTokenSecret + " in ENV")
+ ErrMissingCardmarketApiBaseURL = errors.New("error: missing " + CardmarketApiBaseURL + " in ENV")
)
type CardmarketApiAuth struct {
@@ -77,7 +77,7 @@ func NewConfigFromEnv() (Config, error) {
lvl := slog.LevelInfo
appLogLevel := os.Getenv(AppLogLevel)
if lvlErr := lvl.UnmarshalText([]byte(appLogLevel)); len(appLogLevel) > 0 && lvlErr != nil {
- return Config{}, errors.Join(errors.New("could not unmarshal "+AppLogLevel), lvlErr)
+ return Config{}, errors.Join(errors.New("error: could not unmarshal "+AppLogLevel), lvlErr)
}
return Config{
diff --git a/src/oauth/client.go b/src/oauth/client.go
index 684cb20..fa5d04b 100644
--- a/src/oauth/client.go
+++ b/src/oauth/client.go
@@ -51,6 +51,14 @@ func (c *Client) GetWithContext(
return c.request(ctx, http.MethodGet, url, "", nil)
}
+func (c *Client) PutWithContext(
+ ctx context.Context,
+ url, contentType string,
+ body io.Reader,
+) (*http.Response, error) {
+ return c.request(ctx, http.MethodPut, url, contentType, body)
+}
+
func (c *Client) PostWithContext(
ctx context.Context,
url, contentType string,
@@ -59,6 +67,13 @@ func (c *Client) PostWithContext(
return c.request(ctx, http.MethodPost, url, contentType, body)
}
+func (c *Client) DeleteWithContext(
+ ctx context.Context,
+ url string,
+) (*http.Response, error) {
+ return c.request(ctx, http.MethodDelete, url, "", nil)
+}
+
// request hydrates and fulfils a http.Request using information stored in the client
func (c *Client) request(
ctx context.Context,
@@ -72,7 +87,7 @@ func (c *Client) request(
}
if contentType != "" {
- req.Header.Set("Content-Type", contentType)
+ req.Header.Set(headerContentType, contentType)
}
if err = c.authorize(req); err != nil {