From 2f61b07aea82fa0f5b98686bdfeba2e297c7b21b Mon Sep 17 00:00:00 2001 From: DJ O'Leary Date: Mon, 7 Sep 2026 03:13:01 +0200 Subject: refactor(cardmarket): move handlers to own directory --- src/cardmarket/account.go | 70 ----------------------------- src/cardmarket/game.go | 24 ---------- src/cardmarket/handlers/account.go | 72 ++++++++++++++++++++++++++++++ src/cardmarket/handlers/game.go | 26 +++++++++++ src/cardmarket/handlers/vacation.go | 47 ++++++++++++++++++++ src/cardmarket/http.go | 88 ++++++++++++++++++++++++++++++++++++- src/config/config.go | 12 ++--- src/oauth/client.go | 17 ++++++- 8 files changed, 253 insertions(+), 103 deletions(-) delete mode 100644 src/cardmarket/account.go delete mode 100644 src/cardmarket/game.go create mode 100644 src/cardmarket/handlers/account.go create mode 100644 src/cardmarket/handlers/game.go create mode 100644 src/cardmarket/handlers/vacation.go (limited to 'src') diff --git a/src/cardmarket/account.go b/src/cardmarket/account.go deleted file mode 100644 index bdef2bd..0000000 --- a/src/cardmarket/account.go +++ /dev/null @@ -1,70 +0,0 @@ -package cardmarket - -import ( - "context" -) - -type Account struct { - UserID uint32 `json:"idUser"` - Username string `json:"username"` - Type uint8 `json:"isCommercial"` - Reputation uint8 `json:"reputation"` - SalesCount uint32 `json:"sellCount"` - OnVacation bool `json:"onVacation"` - Country string `json:"country"` - MaySell bool `json:"maySell"` - SellerStatus uint8 `json:"sellerActivation"` - ShipsFast int8 `json:"shipsFast"` - SoldItemCount uint32 `json:"soldItems"` - AvgShippingTime uint8 `json:"avgShippingTime"` - DisplayLanguageID uint8 `json:"idDisplayLanguage"` - Name struct { - First string `json:"firstName"` - Last string `json:"lastName"` - } `json:"name"` - HomeAddress struct { - ReceiverName string `json:"name"` - Extra string `json:"extra"` - Street string `json:"street"` - PostCode string `json:"zip"` - City string `json:"city"` - Country string `json:"country"` - } `json:"homeAddress"` - Email string `json:"email"` - PhoneNumber string `json:"phoneNumber"` - VAT string `json:"vat"` - LegalInformation string `json:"legalInformation"` - RegistrationDate string `json:"registerDate"` - IsActivated bool `json:"isActivated"` - BankAccount struct { - AccountOwner string `json:"accountOwner"` - IBAN string `json:"iban"` - BIC string `json:"bic"` - BankName string `json:"bankName"` - } `json:"bankAccount"` - ArticlesInShoppingCart uint16 `json:"articlesInShoppingCart"` - UnreadMessages uint16 `json:"unreadMessages"` - Wallet struct { - TotalBalance float32 `json:"totalBalance"` - MoneyBalance float32 `json:"moneyBalance"` - BonusBalance float32 `json:"bonusBalance"` - UnpaidAmount float32 `json:"unpaidAmount"` - ProviderRechargeAmount float32 `json:"providerRechargeAmount"` - CurrencyID uint8 `json:"idCurrency"` - CurrencyCode string `json:"currencyCode"` - } `json:"moneyDetails"` - RiskGroup uint8 `json:"riskGroup"` - LossPercentage string `json:"lossPercentage"` -} - -func (c *ApiClient) GetAccountInformation(ctx context.Context) (Account, error) { - type responseBody struct { - Account Account `json:"account"` - Links Links `json:"links"` - } - respBody := &responseBody{} - if err := c.get(ctx, "/account", respBody); err != nil { - return Account{}, err - } - return respBody.Account, 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/handlers/account.go b/src/cardmarket/handlers/account.go new file mode 100644 index 0000000..213766d --- /dev/null +++ b/src/cardmarket/handlers/account.go @@ -0,0 +1,72 @@ +package handlers + +import ( + "context" + + "codeberg.org/dijitol/trading_post/src/cardmarket" +) + +type Account struct { + UserID uint32 `json:"idUser"` + Username string `json:"username"` + Type uint8 `json:"isCommercial"` + Reputation uint8 `json:"reputation"` + SalesCount uint32 `json:"sellCount"` + OnVacation bool `json:"onVacation"` + Country string `json:"country"` + MaySell bool `json:"maySell"` + SellerStatus uint8 `json:"sellerActivation"` + ShipsFast int8 `json:"shipsFast"` + SoldItemCount uint32 `json:"soldItems"` + AvgShippingTime uint8 `json:"avgShippingTime"` + DisplayLanguageID uint8 `json:"idDisplayLanguage"` + Name struct { + First string `json:"firstName"` + Last string `json:"lastName"` + } `json:"name"` + HomeAddress struct { + ReceiverName string `json:"name"` + Extra string `json:"extra"` + Street string `json:"street"` + PostCode string `json:"zip"` + City string `json:"city"` + Country string `json:"country"` + } `json:"homeAddress"` + Email string `json:"email"` + PhoneNumber string `json:"phoneNumber"` + VAT string `json:"vat"` + LegalInformation string `json:"legalInformation"` + RegistrationDate string `json:"registerDate"` + IsActivated bool `json:"isActivated"` + BankAccount struct { + AccountOwner string `json:"accountOwner"` + IBAN string `json:"iban"` + BIC string `json:"bic"` + BankName string `json:"bankName"` + } `json:"bankAccount"` + ArticlesInShoppingCart uint16 `json:"articlesInShoppingCart"` + UnreadMessages uint16 `json:"unreadMessages"` + Wallet struct { + TotalBalance float32 `json:"totalBalance"` + MoneyBalance float32 `json:"moneyBalance"` + BonusBalance float32 `json:"bonusBalance"` + UnpaidAmount float32 `json:"unpaidAmount"` + ProviderRechargeAmount float32 `json:"providerRechargeAmount"` + CurrencyID uint8 `json:"idCurrency"` + CurrencyCode string `json:"currencyCode"` + } `json:"moneyDetails"` + RiskGroup uint8 `json:"riskGroup"` + LossPercentage string `json:"lossPercentage"` +} + +func GetAccountInformation(ctx context.Context, c *cardmarket.ApiClient) (Account, error) { + type responseBody struct { + Account Account `json:"account"` + Links cardmarket.Links `json:"links"` + } + respBody := &responseBody{} + 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 { -- cgit v1.2.3