feat: user defined currencies (#700)

* basic currency service for loading at runtime

* api endpoint for currencies

* sort slice before return

* remove currency validation

* validate using currency service

* implement selecting dynamic currency options

* bump go version

* fix type definition

* specify explicit type

* change go versions

* proper types for assetId

* log/return currency error

* make case insensative

* use ToUpper instead

* feat: adding new currencies (#715)

* fix: task swag (#710)

Co-authored-by: Quoing <pavel.cadersky@mavenir.com>

* [feat] Adding new currencies

---------

Co-authored-by: quoing <quoing@users.noreply.github.com>
Co-authored-by: Quoing <pavel.cadersky@mavenir.com>
Co-authored-by: Bradley <41597815+userbradley@users.noreply.github.com>

* remove ts file and consoldate new values into json

* move flag to options namespace

* add env config for currencies

* basic documentaion

* remove in sync test

---------

Co-authored-by: quoing <quoing@users.noreply.github.com>
Co-authored-by: Quoing <pavel.cadersky@mavenir.com>
Co-authored-by: Bradley <41597815+userbradley@users.noreply.github.com>
Former-commit-id: c4b923847a1b695dcddd1b346adcccfd3f3ce706
This commit is contained in:
Hayden 2024-01-18 13:45:42 -06:00 committed by GitHub
parent ce923a5b4c
commit 2b79788fbe
39 changed files with 1226 additions and 328 deletions

View file

@ -127,6 +127,22 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
}
}
// HandleCurrency godoc
//
// @Summary Currency
// @Tags Base
// @Produce json
// @Success 200 {object} currencies.Currency
// @Router /v1/currency [GET]
func (ctrl *V1Controller) HandleCurrency() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Set Cache for 10 Minutes
w.Header().Set("Cache-Control", "max-age=600")
return server.JSON(w, http.StatusOK, ctrl.svc.Currencies.Slice())
}
}
func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
m := melody.New()

View file

@ -6,6 +6,7 @@ import (
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/homebox/backend/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain"
)
@ -52,6 +53,14 @@ func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
auth := services.NewContext(r.Context())
ok := ctrl.svc.Currencies.IsSupported(body.Currency)
if !ok {
return repo.Group{}, validate.NewFieldErrors(
validate.NewFieldError("currency", "currency '" + body.Currency + "' is not supported"),
)
}
return ctrl.svc.Group.UpdateGroup(auth, body)
}

View file

@ -1,6 +1,7 @@
package main
import (
"bytes"
"context"
"fmt"
"net/http"
@ -13,6 +14,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
"github.com/hay-kot/homebox/backend/internal/data/ent"
@ -126,12 +128,40 @@ func run(cfg *config.Config) error {
return err
}
collectFuncs := []currencies.CollectorFunc{
currencies.CollectDefaults(),
}
if cfg.Options.CurrencyConfig != "" {
log.Info().
Str("path", cfg.Options.CurrencyConfig).
Msg("loading currency config file")
content, err := os.ReadFile(cfg.Options.CurrencyConfig)
if err != nil {
log.Fatal().
Err(err).
Str("path", cfg.Options.CurrencyConfig).
Msg("failed to read currency config file")
}
collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content)))
}
currencies, err := currencies.CollectionCurrencies(collectFuncs...)
if err != nil {
log.Fatal().
Err(err).
Msg("failed to collect currencies")
}
app.bus = eventbus.New()
app.db = c
app.repos = repo.New(c, app.bus, cfg.Storage.Data)
app.services = services.New(
app.repos,
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
services.WithCurrencies(currencies),
)
// =========================================================================

View file

@ -64,6 +64,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
BuildTime: buildTime,
})))
r.Get(v1Base("/currencies"), chain.ToHandlerFunc(v1Ctrl.HandleCurrency()))
providers := []v1.AuthProvider{
providers.NewLocalProvider(a.services.User),
}

View file

@ -150,6 +150,25 @@ const docTemplate = `{
}
}
},
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": {
"get": {
"security": [
@ -410,6 +429,16 @@ const docTemplate = `{
"description": "location Ids",
"name": "locations",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
}
],
"responses": {
@ -1574,7 +1603,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ApiSummary"
"$ref": "#/definitions/v1.APISummary"
}
}
}
@ -1645,6 +1674,12 @@ const docTemplate = `{
"schema": {
"$ref": "#/definitions/v1.LoginForm"
}
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
}
],
"responses": {
@ -1823,6 +1858,23 @@ const docTemplate = `{
}
},
"definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": {
"type": "object",
"properties": {
@ -1998,12 +2050,6 @@ const docTemplate = `{
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@ -2181,8 +2227,7 @@ const docTemplate = `{
"type": "boolean"
},
"assetId": {
"type": "string",
"example": "0"
"type": "string"
},
"description": {
"type": "string"
@ -2736,15 +2781,7 @@ const docTemplate = `{
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"v1.APISummary": {
"type": "object",
"properties": {
"allowRegistration": {
@ -2773,6 +2810,14 @@ const docTemplate = `{
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": {
"type": "object",
"properties": {

View file

@ -143,6 +143,25 @@
}
}
},
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": {
"get": {
"security": [
@ -403,6 +422,16 @@
"description": "location Ids",
"name": "locations",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
}
],
"responses": {
@ -1567,7 +1596,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ApiSummary"
"$ref": "#/definitions/v1.APISummary"
}
}
}
@ -1638,6 +1667,12 @@
"schema": {
"$ref": "#/definitions/v1.LoginForm"
}
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
}
],
"responses": {
@ -1816,6 +1851,23 @@
}
},
"definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": {
"type": "object",
"properties": {
@ -1991,12 +2043,6 @@
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@ -2174,8 +2220,7 @@
"type": "boolean"
},
"assetId": {
"type": "string",
"example": "0"
"type": "string"
},
"description": {
"type": "string"
@ -2729,15 +2774,7 @@
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"v1.APISummary": {
"type": "object",
"properties": {
"allowRegistration": {
@ -2766,6 +2803,14 @@
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": {
"type": "object",
"properties": {

View file

@ -1,5 +1,16 @@
basePath: /api
definitions:
currencies.Currency:
properties:
code:
type: string
local:
type: string
name:
type: string
symbol:
type: string
type: object
repo.DocumentOut:
properties:
id:
@ -116,10 +127,6 @@ definitions:
items:
$ref: '#/definitions/repo.ItemAttachment'
type: array
children:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
createdAt:
type: string
description:
@ -238,7 +245,6 @@ definitions:
archived:
type: boolean
assetId:
example: "0"
type: string
description:
type: string
@ -608,12 +614,7 @@ definitions:
token:
type: string
type: object
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.ApiSummary:
v1.APISummary:
properties:
allowRegistration:
type: boolean
@ -632,6 +633,11 @@ definitions:
type: string
type: array
type: object
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.Build:
properties:
buildTime:
@ -789,6 +795,18 @@ paths:
summary: Get Item by Asset ID
tags:
- Items
/v1/currency:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/currencies.Currency'
summary: Currency
tags:
- Base
/v1/groups:
get:
produces:
@ -942,6 +960,13 @@ paths:
type: string
name: locations
type: array
- collectionFormat: multi
description: parent Ids
in: query
items:
type: string
name: parentIds
type: array
produces:
- application/json
responses:
@ -1656,7 +1681,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/v1.ApiSummary'
$ref: '#/definitions/v1.APISummary'
summary: Application Info
tags:
- Base
@ -1699,6 +1724,10 @@ paths:
required: true
schema:
$ref: '#/definitions/v1.LoginForm'
- description: auth provider
in: query
name: provider
type: string
produces:
- application/json
responses: