mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-04-04 13:46:27 +00:00
tmp tx storage && user repo
This commit is contained in:
parent
658dc000b8
commit
3ac070d12a
@ -3,10 +3,12 @@ module github.com/emochka2007/block-accounting
|
||||
go 1.22.2
|
||||
|
||||
require (
|
||||
github.com/Masterminds/squirrel v1.5.4
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/google/wire v0.6.0
|
||||
github.com/urfave/cli/v2 v2.27.2
|
||||
golang.org/x/crypto v0.18.0
|
||||
@ -15,6 +17,8 @@ require (
|
||||
require (
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
@ -1,7 +1,11 @@
|
||||
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
@ -12,16 +16,25 @@ github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17w
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
|
||||
|
@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
@ -9,6 +10,10 @@ import (
|
||||
"github.com/emochka2007/block-accounting/internal/pkg/bip32"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorAuthInvalidMnemonic = errors.New("Invalid Mnemonic")
|
||||
)
|
||||
|
||||
type AuthController interface {
|
||||
Join(w http.ResponseWriter, req *http.Request) error
|
||||
Login(w http.ResponseWriter, req *http.Request) error
|
||||
@ -34,19 +39,20 @@ func NewAuthController(
|
||||
const mnemonicEntropyBitSize int = 256
|
||||
|
||||
func (c *authController) Join(w http.ResponseWriter, req *http.Request) error {
|
||||
entropy, err := bip32.NewEntropy(mnemonicEntropyBitSize)
|
||||
request, err := c.presenter.CreateJoinRequest(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generate new entropy. %w", err)
|
||||
return fmt.Errorf("error create join request. %w", err)
|
||||
}
|
||||
|
||||
mnemonic, err := bip32.NewMnemonic(entropy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generate mnemonic from entropy. %w", err)
|
||||
c.log.Debug("join request", slog.String("mnemonic", request.Mnemonic))
|
||||
|
||||
if !bip32.IsMnemonicValid(request.Mnemonic) {
|
||||
return fmt.Errorf("error invalid mnemonic. %w", ErrorAuthInvalidMnemonic)
|
||||
}
|
||||
|
||||
// todo create user
|
||||
|
||||
return c.presenter.ResponseJoin(w, mnemonic)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *authController) Login(w http.ResponseWriter, req *http.Request) error {
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type JoinResponse struct {
|
||||
type JoinRequest struct {
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,15 @@ package presenters
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/emochka2007/block-accounting/internal/interface/rest/domain"
|
||||
)
|
||||
|
||||
type AuthPresenter interface {
|
||||
ResponseJoin(w http.ResponseWriter, mnemonic string) error
|
||||
CreateJoinRequest(r *http.Request) (*domain.JoinRequest, error)
|
||||
// ResponseJoin(w http.ResponseWriter, mnemonic string) error
|
||||
}
|
||||
|
||||
type authPresenter struct{}
|
||||
@ -18,17 +20,34 @@ func NewAuthPresenter() AuthPresenter {
|
||||
return &authPresenter{}
|
||||
}
|
||||
|
||||
func (p *authPresenter) ResponseJoin(w http.ResponseWriter, mnemonic string) error {
|
||||
out, err := json.Marshal(domain.JoinResponse{
|
||||
Mnemonic: mnemonic,
|
||||
})
|
||||
func (p *authPresenter) CreateJoinRequest(r *http.Request) (*domain.JoinRequest, error) {
|
||||
defer r.Body.Close()
|
||||
|
||||
data, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshal join response. %w", err)
|
||||
return nil, fmt.Errorf("error read request body. %w", err)
|
||||
}
|
||||
|
||||
if _, err = w.Write(out); err != nil {
|
||||
return fmt.Errorf("error write response. %w", err)
|
||||
var request domain.JoinRequest
|
||||
|
||||
if err := json.Unmarshal(data, &request); err != nil {
|
||||
return nil, fmt.Errorf("error unmarshal join request. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return &request, nil
|
||||
}
|
||||
|
||||
// func (p *authPresenter) ResponseJoin(w http.ResponseWriter, mnemonic string) error {
|
||||
// out, err := json.Marshal(domain.JoinResponse{
|
||||
// Mnemonic: mnemonic,
|
||||
// })
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("error marshal join response. %w", err)
|
||||
// }
|
||||
|
||||
// if _, err = w.Write(out); err != nil {
|
||||
// return fmt.Errorf("error write response. %w", err)
|
||||
// }
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
@ -92,7 +92,7 @@ func (s *Server) buildRouter() {
|
||||
r.Delete("/{tx_id}", nil) // remove
|
||||
})
|
||||
|
||||
s.Post("/invite", nil) // create a new invite link
|
||||
s.Post("/invite/{hash}", nil) // create a new invite link
|
||||
|
||||
s.Route("/employees", func(r chi.Router) {
|
||||
r.Get("/", nil) // list
|
||||
|
38
backend/internal/pkg/models/tx.go
Normal file
38
backend/internal/pkg/models/tx.go
Normal file
@ -0,0 +1,38 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Transaction struct {
|
||||
Id uuid.UUID
|
||||
|
||||
Description string
|
||||
OrganizationId uuid.UUID
|
||||
CreatedBy *User
|
||||
Amount int64
|
||||
|
||||
ToAddr []byte
|
||||
|
||||
MaxFeeAllowed int64
|
||||
Deadline time.Time
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
ConfirmedAt time.Time
|
||||
CancelledAt time.Time
|
||||
|
||||
CommitedAt time.Time
|
||||
}
|
||||
|
||||
type TransactionConfirmation struct {
|
||||
TxId uuid.UUID
|
||||
User *User
|
||||
OrganizationId uuid.UUID
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Confirmed bool
|
||||
}
|
@ -1,34 +1,39 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserIdentity interface {
|
||||
Id() string
|
||||
Mnemonic() string
|
||||
Id() uuid.UUID
|
||||
Seed() []byte
|
||||
IsAdmin() bool
|
||||
}
|
||||
|
||||
type User struct {
|
||||
id string
|
||||
mnemonic string
|
||||
isAdmin bool
|
||||
ID uuid.UUID
|
||||
Bip32Seed []byte
|
||||
Admin bool
|
||||
Activated bool
|
||||
}
|
||||
|
||||
func NewUser(id string, mnemonic string) *User {
|
||||
func NewUser(id uuid.UUID, seed []byte) *User {
|
||||
return &User{
|
||||
id: id,
|
||||
mnemonic: mnemonic,
|
||||
ID: id,
|
||||
Bip32Seed: seed,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) Id() string {
|
||||
return u.id
|
||||
func (u *User) Id() uuid.UUID {
|
||||
return u.ID
|
||||
}
|
||||
|
||||
func (u *User) Mnemonic() string {
|
||||
return u.mnemonic
|
||||
func (u *User) Seed() []byte {
|
||||
return u.Bip32Seed
|
||||
}
|
||||
|
||||
func (u *User) IsAdmin() bool {
|
||||
return u.isAdmin
|
||||
return u.Admin
|
||||
}
|
||||
|
||||
type OrganizationUser struct {
|
||||
|
@ -21,7 +21,7 @@ type TransactionalStorage interface {
|
||||
Conn(ctx context.Context) DBTX
|
||||
}
|
||||
|
||||
type txCtxKey struct{}
|
||||
type TxCtxKey struct{}
|
||||
|
||||
func Transaction(ctx context.Context, db *sql.DB, fn func(context.Context) error) error {
|
||||
var err error
|
||||
@ -70,14 +70,14 @@ func Transaction(ctx context.Context, db *sql.DB, fn func(context.Context) error
|
||||
return fmt.Errorf("error begin transaction. %w", err)
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, txCtxKey{}, tx)
|
||||
ctx = context.WithValue(ctx, TxCtxKey{}, tx)
|
||||
}
|
||||
|
||||
return fn(ctx)
|
||||
}
|
||||
|
||||
func hasExternalTransaction(ctx context.Context) bool {
|
||||
if _, ok := ctx.Value(txCtxKey{}).(*sql.Tx); ok {
|
||||
if _, ok := ctx.Value(TxCtxKey{}).(*sql.Tx); ok {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
package smartcontract
|
||||
|
||||
type SmartContractInteractor interface {
|
||||
}
|
316
backend/internal/usecase/repository/transactions/repository.go
Normal file
316
backend/internal/usecase/repository/transactions/repository.go
Normal file
@ -0,0 +1,316 @@
|
||||
package transactions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/emochka2007/block-accounting/internal/pkg/models"
|
||||
sqltools "github.com/emochka2007/block-accounting/internal/pkg/sqlutils"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type GetTransactionsFilter int
|
||||
|
||||
const (
|
||||
GetFilterExpired GetTransactionsFilter = iota
|
||||
GetFilterNonExpired
|
||||
GetFilterCancelled
|
||||
GetFilterConfirmed
|
||||
GetFilterCommited
|
||||
)
|
||||
|
||||
type GetTransactionsParams struct {
|
||||
Ids uuid.UUIDs
|
||||
OrganizationId uuid.UUID
|
||||
CreatedById uuid.UUID
|
||||
To []byte
|
||||
Filters []GetTransactionsFilter
|
||||
}
|
||||
|
||||
type ConfirmTransactionParams struct {
|
||||
TxId uuid.UUID
|
||||
UserId uuid.UUID
|
||||
OrganizationId uuid.UUID
|
||||
}
|
||||
|
||||
type CancelTransactionParams struct {
|
||||
TxId uuid.UUID
|
||||
UserId uuid.UUID
|
||||
OrganizationId uuid.UUID
|
||||
}
|
||||
|
||||
type Repository interface {
|
||||
GetTransactions(ctx context.Context, params GetTransactionsParams) ([]*models.Transaction, error)
|
||||
CreateTransaction(ctx context.Context, tx models.Transaction) error
|
||||
UpdateTransaction(ctx context.Context, tx models.Transaction) error
|
||||
DeleteTransaction(ctx context.Context, tx models.Transaction) error
|
||||
|
||||
ConfirmTransaction(ctx context.Context, params ConfirmTransactionParams) error
|
||||
CancelTransaction(ctx context.Context, params CancelTransactionParams) error
|
||||
}
|
||||
|
||||
type repositorySQL struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (s *repositorySQL) Conn(ctx context.Context) sqltools.DBTX {
|
||||
if tx, ok := ctx.Value(sqltools.TxCtxKey{}).(*sql.Tx); ok {
|
||||
return tx
|
||||
}
|
||||
|
||||
return s.db
|
||||
}
|
||||
|
||||
func (r *repositorySQL) GetTransactions(
|
||||
ctx context.Context,
|
||||
params GetTransactionsParams,
|
||||
) ([]*models.Transaction, error) {
|
||||
var txs []*models.Transaction = make([]*models.Transaction, 0, len(params.Ids))
|
||||
err := sqltools.Transaction(ctx, r.db, func(ctx context.Context) (err error) {
|
||||
query := buildGetTransactionsQuery(params)
|
||||
|
||||
rows, err := query.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetch transactions data from database. %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if cErr := rows.Close(); cErr != nil {
|
||||
err = errors.Join(fmt.Errorf("error close database rows. %w", cErr), err)
|
||||
}
|
||||
}()
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
id uuid.UUID
|
||||
description string
|
||||
organizationId uuid.UUID
|
||||
amount int64
|
||||
toAddr []byte
|
||||
maxFeeAllowed int64
|
||||
deadline sql.NullTime
|
||||
createdAt time.Time
|
||||
updatedAt time.Time
|
||||
confirmedAt sql.NullTime
|
||||
cancelledAt sql.NullTime
|
||||
commitedAt sql.NullTime
|
||||
|
||||
createdById uuid.UUID
|
||||
createdBySeed []byte
|
||||
createdByCreatedAt time.Time
|
||||
createdByActivatedAt sql.NullTime
|
||||
createdByIsAdmin bool
|
||||
)
|
||||
|
||||
if err = rows.Scan(
|
||||
&id,
|
||||
&description,
|
||||
&organizationId,
|
||||
&amount,
|
||||
&toAddr,
|
||||
&maxFeeAllowed,
|
||||
&deadline,
|
||||
&createdAt,
|
||||
&updatedAt,
|
||||
&confirmedAt,
|
||||
&cancelledAt,
|
||||
&commitedAt,
|
||||
|
||||
&createdById,
|
||||
&createdBySeed,
|
||||
&createdByCreatedAt,
|
||||
&createdByActivatedAt,
|
||||
&createdByIsAdmin,
|
||||
); err != nil {
|
||||
return fmt.Errorf("error scan row. %w", err)
|
||||
}
|
||||
|
||||
tx := &models.Transaction{
|
||||
Id: id,
|
||||
Description: description,
|
||||
OrganizationId: organizationId,
|
||||
Amount: amount,
|
||||
ToAddr: toAddr,
|
||||
MaxFeeAllowed: maxFeeAllowed,
|
||||
CreatedBy: &models.User{
|
||||
ID: createdById,
|
||||
Bip32Seed: createdBySeed,
|
||||
},
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
|
||||
if deadline.Valid {
|
||||
tx.Deadline = deadline.Time
|
||||
}
|
||||
|
||||
if confirmedAt.Valid {
|
||||
tx.ConfirmedAt = confirmedAt.Time
|
||||
}
|
||||
|
||||
if commitedAt.Valid {
|
||||
tx.CommitedAt = commitedAt.Time
|
||||
}
|
||||
|
||||
if cancelledAt.Valid {
|
||||
tx.CancelledAt = cancelledAt.Time
|
||||
}
|
||||
|
||||
if createdByActivatedAt.Valid {
|
||||
tx.CreatedBy.Activated = true
|
||||
}
|
||||
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error execute transactional operation. %w", err)
|
||||
}
|
||||
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
func (r *repositorySQL) CreateTransaction(ctx context.Context, tx models.Transaction) error {
|
||||
if err := sqltools.Transaction(ctx, r.db, func(ctx context.Context) error {
|
||||
query := sq.Insert("transactions").Columns(
|
||||
"t.id",
|
||||
"t.description",
|
||||
"t.organization_id",
|
||||
"t.created_by",
|
||||
"t.amount",
|
||||
"t.to_addr",
|
||||
"t.max_fee_allowed",
|
||||
|
||||
// todo insert later
|
||||
// "t.deadline",
|
||||
// "t.created_at",
|
||||
// "t.updated_at",
|
||||
// "t.confirmed_at",
|
||||
// "t.cancelled_at",
|
||||
// "t.commited_at",
|
||||
).Values(
|
||||
tx.Id,
|
||||
tx.Description,
|
||||
tx.OrganizationId,
|
||||
tx.CreatedBy.ID,
|
||||
tx.Amount,
|
||||
tx.ToAddr,
|
||||
tx.MaxFeeAllowed,
|
||||
)
|
||||
|
||||
// todo add optional insertions
|
||||
|
||||
if _, err := query.RunWith(r.Conn(ctx)).ExecContext(ctx); err != nil {
|
||||
return fmt.Errorf("error insert new transaction. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error execute transactional operation. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositorySQL) UpdateTransaction(ctx context.Context, tx models.Transaction) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositorySQL) DeleteTransaction(ctx context.Context, tx models.Transaction) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositorySQL) ConfirmTransaction(ctx context.Context, params ConfirmTransactionParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositorySQL) CancelTransaction(ctx context.Context, params CancelTransactionParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildGetTransactionsQuery(params GetTransactionsParams) sq.SelectBuilder {
|
||||
query := sq.Select(
|
||||
`t.id,
|
||||
t.description,
|
||||
t.organization_id,
|
||||
t.created_by,
|
||||
t.amount,
|
||||
t.to_addr,
|
||||
t.max_fee_allowed,
|
||||
t.deadline,
|
||||
t.created_at,
|
||||
t.updated_at,
|
||||
t.confirmed_at,
|
||||
t.cancelled_at,
|
||||
t.commited_at,
|
||||
|
||||
u.id,
|
||||
u.seed,
|
||||
u.created_at,
|
||||
u.activated_at,
|
||||
u.is_admin`,
|
||||
).From("transactions as t").
|
||||
InnerJoin("users as u on u.id = t.created_by").
|
||||
Where(sq.Eq{
|
||||
"t.organization_id": params.OrganizationId,
|
||||
})
|
||||
|
||||
if len(params.Ids) > 0 {
|
||||
query = query.Where(sq.Eq{
|
||||
"t.id": params.Ids,
|
||||
})
|
||||
}
|
||||
|
||||
if params.CreatedById != uuid.Nil {
|
||||
query = query.Where(sq.Eq{
|
||||
"t.created_by": params.CreatedById,
|
||||
})
|
||||
}
|
||||
|
||||
if params.OrganizationId != uuid.Nil {
|
||||
query = query.Where(sq.Eq{
|
||||
"t.organization_id": params.OrganizationId,
|
||||
})
|
||||
}
|
||||
|
||||
if params.To != nil {
|
||||
query = query.Where(sq.Eq{
|
||||
"t.to_addr": params.To,
|
||||
})
|
||||
}
|
||||
|
||||
if slices.Contains(params.Filters, GetFilterExpired) {
|
||||
query = query.Where(sq.LtOrEq{
|
||||
"t.deadline": time.Now(),
|
||||
})
|
||||
} else if slices.Contains(params.Filters, GetFilterNonExpired) {
|
||||
query = query.Where(sq.GtOrEq{
|
||||
"t.deadline": time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
if slices.Contains(params.Filters, GetFilterCancelled) {
|
||||
query = query.Where(sq.NotEq{
|
||||
"t.cancelled_at": nil,
|
||||
})
|
||||
} else if slices.Contains(params.Filters, GetFilterConfirmed) {
|
||||
query = query.Where(sq.NotEq{
|
||||
"t.confirmed_at": nil,
|
||||
})
|
||||
}
|
||||
|
||||
if slices.Contains(params.Filters, GetFilterCommited) {
|
||||
query = query.Where(sq.NotEq{
|
||||
"t.commited_at": nil,
|
||||
})
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
74
backend/migrations/blockd.sql
Normal file
74
backend/migrations/blockd.sql
Normal file
@ -0,0 +1,74 @@
|
||||
create table if not exists users (
|
||||
id uuid not null,
|
||||
seed bytea not null unique,
|
||||
created_at timestamp default current_timestamp,
|
||||
activated_at timestamp default null,
|
||||
primary key (id, seed)
|
||||
);
|
||||
|
||||
create table if not exists organizations (
|
||||
id uuid primary key,
|
||||
name varchar(300) default 'My Organization' not null,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp
|
||||
);
|
||||
|
||||
create index if not exists index_organizations_id
|
||||
on organizations (id);
|
||||
|
||||
create table organizations_users (
|
||||
organization_id uuid not null,
|
||||
user_id uuid not null,
|
||||
added_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp,
|
||||
is_admin bool default false,
|
||||
primary key(organization_id, user_id)
|
||||
);
|
||||
|
||||
create index if not exists index_organizations_users_organization_id_user_id_is_admin
|
||||
on organizations_users (organization_id, user_id, is_admin);
|
||||
|
||||
create index if not exists index_organizations_users_organization_id_user_id
|
||||
on organizations_users (organization_id, user_id);
|
||||
|
||||
create table if not exists transactions (
|
||||
id uuid primary key,
|
||||
description text default 'New Transaction',
|
||||
organization_id uuid not null,
|
||||
created_by uuid not null,
|
||||
amount bigint default 0,
|
||||
|
||||
to_addr bytea not null,
|
||||
|
||||
max_fee_allowed bigint default 0,
|
||||
deadline timestamp default null,
|
||||
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp,
|
||||
|
||||
confirmed_at timestamp default null,
|
||||
cancelled_at timestamp default null,
|
||||
|
||||
commited_at timestamp default null
|
||||
);
|
||||
|
||||
create index if not exists index_transactions_id_organization_id
|
||||
on transactions (organization_id);
|
||||
|
||||
create index if not exists index_transactions_id_organization_id_created_by
|
||||
on transactions (organization_id, created_by);
|
||||
|
||||
create index if not exists index_transactions_organization_id_deadline
|
||||
on transactions (organization_id, deadline);
|
||||
|
||||
create table transactions_confirmations (
|
||||
tx_id uuid not null,
|
||||
user_id uuid not null,
|
||||
organization_id uuid not null,
|
||||
created_at timestamp default current_timestamp,
|
||||
updated_at timestamp default current_timestamp,
|
||||
confirmed bool
|
||||
);
|
||||
|
||||
create index if not exists index_transactions_confirmations_tx_id_user_id_organization_id
|
||||
on transactions_confirmations (tx_id, user_id, organization_id);
|
Loading…
Reference in New Issue
Block a user