Skip to content
This repository has been archived by the owner on Oct 31, 2021. It is now read-only.

Commit

Permalink
More work on API.
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotcourant committed Feb 27, 2021
1 parent 7b24456 commit 95992eb
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 45 deletions.
5 changes: 5 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func (c *Controller) RegisterRoutes(app *iris.Application) {
p.PartyFunc("/links", c.linksController)

p.PartyFunc("/plaid/link", c.handlePlaidLinkEndpoints)

p.PartyFunc("/bank_accounts", func(p router.Party) {
c.handleBankAccounts(p)
c.handleTransactions(p)
})
})

}
68 changes: 53 additions & 15 deletions pkg/controller/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,60 @@ package controller
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/router"
"net/http"
)

func (c *Controller) transactionsController(p iris.Party) {
p.Get("/", func(ctx *context.Context) {

})

p.Post("/", func(ctx *context.Context) {

})

p.Put("/{transactionId:uint64}", func(ctx *context.Context) {

})

p.Delete("/{transactionId:uint64}", func(ctx *context.Context) {

func (c *Controller) handleTransactions(p iris.Party) {
p.PartyFunc("/{bankAccountId:uint64}/transactions", func(p router.Party) {
p.Get("/", func(ctx *context.Context) {
bankAccountId := ctx.Params().GetUint64Default("bankAccountId", 0)
if bankAccountId == 0 {
c.returnError(ctx, http.StatusBadRequest, "must specify valid bank account Id")
return
}

// TODO Enforce a max limit for the number of transactions that can be requested.
limit := ctx.URLParamIntDefault("limit", 25)
offset := ctx.URLParamIntDefault("offset", 0)

repo := c.mustGetAuthenticatedRepository(ctx)

transactions, err := repo.GetTransactions(bankAccountId, limit, offset)
if err != nil {
c.wrapPgError(ctx, err, "failed to retrieve transactions")
return
}

ctx.JSON(map[string]interface{}{
"transactions": transactions,
})
})

p.Post("/", func(ctx *context.Context) {
bankAccountId := ctx.Params().GetUint64Default("bankAccountId", 0)
if bankAccountId == 0 {
c.returnError(ctx, http.StatusBadRequest, "must specify valid bank account Id")
return
}
})

p.Put("/{transactionId:uint64}", func(ctx *context.Context) {
bankAccountId := ctx.Params().GetUint64Default("bankAccountId", 0)
if bankAccountId == 0 {
c.returnError(ctx, http.StatusBadRequest, "must specify valid bank account Id")
return
}

})

p.Delete("/{transactionId:uint64}", func(ctx *context.Context) {
bankAccountId := ctx.Params().GetUint64Default("bankAccountId", 0)
if bankAccountId == 0 {
c.returnError(ctx, http.StatusBadRequest, "must specify valid bank account Id")
return
}

})
})
}
8 changes: 8 additions & 0 deletions pkg/jobs/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/plaid/plaid-go/plaid"
"github.com/sirupsen/logrus"
"math"
"time"
)

type JobManager interface {
Expand Down Expand Up @@ -80,7 +81,14 @@ func (j *jobManagerBase) TriggerPullInitialTransactions(accountId, userId, linkI
}

func (j *jobManagerBase) middleware(job *work.Job, next work.NextMiddlewareFunc) error {
start := time.Now()
j.log.WithField("jobId", job.ID).WithField("name", job.Name).Infof("starting job")
defer func() {
j.log.WithField("jobId", job.ID).WithField("name", job.Name).Infof("finished job")
if j.stats != nil {
j.stats.JobFinished(job.Name, uint64(job.ArgInt64("accountId")), start)
}
}()
return next()
}

Expand Down
5 changes: 4 additions & 1 deletion pkg/jobs/pull_latest_transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ func (j *jobManagerBase) pullLatestTransactions(job *work.Job) error {
plaidTransactionIds[i] = transaction.ID
}

// TODO This is causing existing transactions to be re-inserted somehow.
transactionIds, err := repo.GetTransactionsByPlaidId(linkId, plaidTransactionIds)
if err != nil {
log.WithError(err).Error("failed to retrieve transaction ids for updating plaid transactions")
Expand Down Expand Up @@ -193,6 +192,10 @@ func (j *jobManagerBase) pullLatestTransactions(job *work.Job) error {
}

if len(transactionsToInsert) > 0 {
// Reverse the list so the oldest records are inserted first.
for i, j := 0, len(transactionsToInsert)-1; i < j; i, j = i+1, j-1 {
transactionsToInsert[i], transactionsToInsert[j] = transactionsToInsert[j], transactionsToInsert[i]
}
if err = repo.InsertTransactions(transactionsToInsert); err != nil {
log.WithError(err).Error("failed to insert new transactions")
return err
Expand Down
4 changes: 2 additions & 2 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ func (s *Stats) JobFinished(name string, accountId uint64, start time.Time) {

func (s *Stats) FinishedRequest(ctx *context.Context, responseTime time.Duration) {
s.HTTPRequests.With(prometheus.Labels{
"path": ctx.Path(),
"path": ctx.RouteName(),
"method": ctx.Method(),
"status": strconv.FormatInt(int64(ctx.GetStatusCode()), 10),
}).Inc()
s.HTTPResponseTime.With(prometheus.Labels{
"path": ctx.Path(),
"path": ctx.RouteName(),
"method": ctx.Method(),
"status": strconv.FormatInt(int64(ctx.GetStatusCode()), 10),
}).Observe(float64(responseTime.Milliseconds()))
Expand Down
23 changes: 4 additions & 19 deletions pkg/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ type Repository interface {

CreateBankAccounts(bankAccounts ...models.BankAccount) error
CreateLink(link *models.Link) error
UpdateLink(link *models.Link) error
CreatePlaidLink(link *models.PlaidLink) error
GetBankAccounts() ([]models.BankAccount, error)
GetBankAccountsByLinkId(linkId uint64) ([]models.BankAccount, error)
UpdateBankAccounts(accounts []models.BankAccount) error
GetIsSetup() (bool, error)
GetLink(linkId uint64) (*models.Link, error)
GetLinks() ([]models.Link, error)
GetMe() (*models.User, error)
InsertTransactions(transactions []models.Transaction) error
GetTransactions(bankAccountId uint64, limit, offset int) ([]models.Transaction, error)
GetTransactionsByPlaidId(linkId uint64, plaidTransactionIds []string) (map[string]TransactionUpdateId, error)
InsertTransactions(transactions []models.Transaction) error
UpdateBankAccounts(accounts []models.BankAccount) error
UpdateLink(link *models.Link) error
}

type UnauthenticatedRepository interface {
Expand Down Expand Up @@ -117,19 +118,3 @@ func (r *repositoryBase) GetFundingSchedules(bankAccountId uint64) ([]models.Fun
Select(&result)
return result, errors.Wrap(err, "failed to retrieve funding schedules")
}

func (r *repositoryBase) CreateTransaction(transaction *models.Transaction) error {
transaction.AccountId = r.AccountId()
_, err := r.txn.Model(transaction).Insert(transaction)
return errors.Wrap(err, "failed to create transaction")
}

func (r *repositoryBase) GetTransactions(bankAccountId uint64) ([]models.Transaction, error) {
var result []models.Transaction
err := r.txn.Model(&result).
Where(`"transaction"."account_id" = ? AND "transaction"."bank_account_id" = ?`, r.AccountId(), bankAccountId).
Order(`"transaction"."transaction_id" DESC`).
Limit(25).
Select(&result)
return result, err
}
21 changes: 19 additions & 2 deletions pkg/repository/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (r *repositoryBase) InsertTransactions(transactions []models.Transaction) e
func (r *repositoryBase) GetTransactionsByPlaidId(linkId uint64, plaidTransactionIds []string) (map[string]TransactionUpdateId, error) {
type Transaction struct {
tableName string `pg:"transactions"`
plaidTransactionId string `pg:"plaid_transaction_id"`
PlaidTransactionId string `pg:"plaid_transaction_id"`
TransactionUpdateId
}
var items []Transaction
Expand All @@ -39,8 +39,25 @@ func (r *repositoryBase) GetTransactionsByPlaidId(linkId uint64, plaidTransactio

result := map[string]TransactionUpdateId{}
for _, item := range items {
result[item.plaidTransactionId] = item.TransactionUpdateId
result[item.PlaidTransactionId] = item.TransactionUpdateId
}

return result, nil
}

func (r *repositoryBase) GetTransactions(bankAccountId uint64, limit, offset int) ([]models.Transaction, error) {
var items []models.Transaction
err := r.txn.Model(&items).
Where(`"transaction"."account_id" = ?`, r.AccountId()).
Where(`"transaction"."bank_account_id" = ?`, bankAccountId).
Limit(limit).
Offset(offset).
Order(`date DESC`).
Order(`transaction_id DESC`).
Select(&items)
if err != nil {
return nil, errors.Wrap(err, "failed to retrieve transactions")
}

return items, nil
}
12 changes: 6 additions & 6 deletions schema/00000000_Initial.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ CREATE TABLE IF NOT EXISTS "bank_accounts"
"account_type" text,
"account_sub_type" text,
PRIMARY KEY ("bank_account_id", "account_id"),
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE,
FOREIGN KEY ("link_id", "account_id") REFERENCES "links" ("link_id", "account_id") ON DELETE CASCADE
FOREIGN KEY ("link_id", "account_id") REFERENCES "links" ("link_id", "account_id") ON DELETE CASCADE,
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "funding_schedules"
Expand Down Expand Up @@ -159,9 +159,9 @@ CREATE TABLE IF NOT EXISTS "expenses"
"is_behind" boolean NOT NULL,
PRIMARY KEY ("expense_id", "account_id", "bank_account_id"),
UNIQUE ("bank_account_id", "name"),
FOREIGN KEY ("bank_account_id", "account_id") REFERENCES "bank_accounts" ("bank_account_id", "account_id") ON DELETE CASCADE,
FOREIGN KEY ("funding_schedule_id", "account_id", "bank_account_id") REFERENCES "funding_schedules" ("funding_schedule_id", "account_id", "bank_account_id") ON DELETE SET NULL,
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE,
FOREIGN KEY ("bank_account_id", "account_id") REFERENCES "bank_accounts" ("bank_account_id", "account_id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "transactions"
Expand All @@ -184,9 +184,9 @@ CREATE TABLE IF NOT EXISTS "transactions"
"created_at" timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY ("transaction_id", "account_id", "bank_account_id"),
UNIQUE ("bank_account_id", "plaid_transaction_id"),
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE,
FOREIGN KEY ("bank_account_id", "account_id") REFERENCES "bank_accounts" ("bank_account_id", "account_id") ON DELETE CASCADE,
FOREIGN KEY ("expense_id", "account_id", "bank_account_id") REFERENCES "expenses" ("expense_id", "account_id", "bank_account_id") ON DELETE SET NULL
FOREIGN KEY ("expense_id", "account_id", "bank_account_id") REFERENCES "expenses" ("expense_id", "account_id", "bank_account_id") ON DELETE SET NULL,
FOREIGN KEY ("account_id") REFERENCES "accounts" ("account_id") ON DELETE CASCADE
);

INSERT INTO "logins" ("login_id", "email", "password_hash", "phone_number", "is_enabled", "is_email_verified",
Expand Down

0 comments on commit 95992eb

Please sign in to comment.