Skip to content

Commit

Permalink
feat: accounts list (#80)
Browse files Browse the repository at this point in the history
* feat: accounts list

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>

* fix: add required fields to OAS

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>
  • Loading branch information
darkmatterpool authored Jan 6, 2023
1 parent 0c89897 commit dea61f0
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 1 deletion.
107 changes: 107 additions & 0 deletions internal/app/api/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package api

import (
"context"
"encoding/json"
"net/http"
"strings"
"time"

"github.com/formancehq/payments/internal/app/models"
"github.com/formancehq/payments/internal/app/storage"

"github.com/formancehq/go-libs/sharedapi"
"github.com/pkg/errors"
)

type listAccountsRepository interface {
ListAccounts(ctx context.Context, sort storage.Sorter, pagination storage.Paginator) ([]*models.Account, error)
}

type accountResponse struct {
ID string `json:"id"`
Reference string `json:"reference"`
CreatedAt time.Time `json:"createdAt"`
Provider string `json:"provider"`
Type models.AccountType `json:"type"`
}

func listAccountsHandler(repo listAccountsRepository) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

var sorter storage.Sorter

if sortParams := r.URL.Query()["sort"]; sortParams != nil {
for _, s := range sortParams {
parts := strings.SplitN(s, ":", 2)

var order storage.SortOrder

if len(parts) > 1 {
//nolint:goconst // allow duplicate string
switch parts[1] {
case "asc", "ASC":
order = storage.SortOrderAsc
case "dsc", "desc", "DSC", "DESC":
order = storage.SortOrderDesc
default:
handleValidationError(w, r, errors.New("sort order not well specified, got "+parts[1]))

return
}
}

column := parts[0]

sorter.Add(column, order)
}
}

skip, err := integerWithDefault(r, "skip", 0)
if err != nil {
handleValidationError(w, r, err)

return
}

limit, err := integerWithDefault(r, "limit", maxPerPage)
if err != nil {
handleValidationError(w, r, err)

return
}

if limit > maxPerPage {
limit = maxPerPage
}

ret, err := repo.ListAccounts(r.Context(), sorter, storage.Paginate(skip, limit))
if err != nil {
handleServerError(w, r, err)

return
}

data := make([]*accountResponse, len(ret))

for i := range ret {
data[i] = &accountResponse{
ID: ret[i].ID.String(),
Reference: ret[i].Reference,
CreatedAt: ret[i].CreatedAt,
Provider: ret[i].Provider,
Type: ret[i].Type,
}
}

err = json.NewEncoder(w).Encode(sharedapi.BaseResponse[[]*accountResponse]{
Data: &data,
})
if err != nil {
handleServerError(w, r, err)

return
}
}
}
2 changes: 2 additions & 0 deletions internal/app/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func httpRouter(store *storage.Storage, connectorHandlers []connectorHandler) (*
authGroup.Path("/payments").Methods(http.MethodGet).Handler(listPaymentsHandler(store))
authGroup.Path("/payments/{paymentID}").Methods(http.MethodGet).Handler(readPaymentHandler(store))

authGroup.Path("/accounts").Methods(http.MethodGet).Handler(listAccountsHandler(store))

authGroup.HandleFunc("/connectors", readConnectorsHandler(store))

connectorGroup := authGroup.PathPrefix("/connectors").Subrouter()
Expand Down
1 change: 1 addition & 0 deletions internal/app/connectors/wise/task_fetch_transfers.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func taskFetchTransfers(logger sharedlogging.Logger, client *client, profileID u
accountBatch = append(accountBatch,
ingestion.AccountBatchElement{
Reference: ref,
Provider: models.ConnectorProviderWise.String(),
Type: models.AccountTypeTarget,
},
)
Expand Down
21 changes: 21 additions & 0 deletions internal/app/storage/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package storage

import (
"context"
"fmt"

"github.com/formancehq/payments/internal/app/models"
)
Expand Down Expand Up @@ -33,3 +34,23 @@ func (s *Storage) UpsertAccounts(ctx context.Context, provider models.ConnectorP

return nil
}

func (s *Storage) ListAccounts(ctx context.Context, sort Sorter, pagination Paginator) ([]*models.Account, error) {
var accounts []*models.Account

query := s.db.NewSelect().
Model(&accounts)

if sort != nil {
query = sort.apply(query)
}

query = pagination.apply(query)

err := query.Scan(ctx)
if err != nil {
return nil, fmt.Errorf("failed to list payments: %w", err)
}

return accounts, nil
}
68 changes: 67 additions & 1 deletion swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Payment'
/accounts:
get:
summary: Returns a list of accounts.
operationId: listAccounts
tags:
- Payments
parameters:
- name: limit
in: query
schema:
type: integer
description: Limit the number of accounts to return, pagination can be achieved in conjunction with 'skip' parameter.
example: 10
- name: skip
in: query
schema:
type: integer
description: How many accounts to skip, pagination can be achieved in conjunction with 'limit' parameter.
example: 100
- name: sort
in: query
schema:
type: array
items:
type: string
description: Field used to sort payments (Default is by date).
example: status
responses:
'200': # status code
description: A JSON array of accounts
content:
application/json:
schema:
$ref: '#/components/schemas/ListAccountsResponse'
/connectors:
get:
summary: Get all installed connectors
Expand Down Expand Up @@ -452,7 +486,39 @@ components:
format: date-time
raw:
nullable: true

ListAccountsResponse:
type: object
required:
- data
properties:
data:
type: array
items:
$ref: '#/components/schemas/Account'
Account:
type: object
required:
- id
- createdAt
- provider
- reference
- type
properties:
id:
type: string
createdAt:
type: string
format: date-time
provider:
type: string
reference:
type: string
type:
type: string
enum:
- TARGET
- SOURCE

ListConnectorsResponse:
type: object
required:
Expand Down

0 comments on commit dea61f0

Please sign in to comment.