Commit faadbe0c authored by Alexis POYEN's avatar Alexis POYEN
Browse files

Feat : manage bank account without authent

parent 502cef6e
Pipeline #4470 failed with stages
in 3 minutes and 8 seconds
......@@ -4,14 +4,15 @@ go 1.14
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.3.4 // indirect
github.com/golang/protobuf v1.3.5 // indirect
github.com/jinzhu/gorm v1.9.12
github.com/kr/pretty v0.1.0 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/oschwald/maxminddb-golang v1.6.0
github.com/secure-io/sio-go v0.3.0
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d // indirect
google.golang.org/appengine v1.6.5 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
)
......@@ -2,35 +2,54 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/oschwald/maxminddb-golang v1.6.0 h1:KAJSjdHQ8Kv45nFIbtoLGrGWqHFajOIm7skTyz/+Dls=
github.com/oschwald/maxminddb-golang v1.6.0/go.mod h1:DUJFucBg2cvqx42YmDa/+xHvb0elJtOm3o4aFQ/nb/w=
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/secure-io/sio-go v0.3.0 h1:QKGb6rGJeiExac9wSWxnWPYo8O8OFN7lxXQvHshX6vo=
github.com/secure-io/sio-go v0.3.0/go.mod h1:D3KmXgKETffyYxBdFRN+Hpd2WzhzqS0EQwT3XWsAcBU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 h1:TjszyFsQsyZNHwdVdZ5m7bjmreu0znc2kRYsEml9/Ww=
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec h1:w0SItUiQ4sBiXBAwWNkyu8Fu2Qpn/dtDIcoPkPDqjRw=
golang.org/x/net v0.0.0-20200319234117-63522dbf7eec/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
......@@ -38,8 +57,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciMoV+FeI1sRXx/pLDL44=
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
......
package models
import (
"net/http"
"strconv"
"strings"
"time"
"encoding/json"
"github.com/jinzhu/gorm"
// Needed for sqlite
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
// DataHandler init a gorm DB an presents API handlers
type DataHandler struct {
db *gorm.DB
}
// NewDataHandler init a DataHandler and returns a pointer to it
func NewDataHandler() *DataHandler {
db, err := gorm.Open("sqlite3", "../../data/test.db")
if err != nil {
panic("failed to connect database")
}
db.LogMode(true)
db.Model(&Operation{}).AddForeignKey("creditor", "bank_account(id)", "RESTRICT", "RESTRICT")
// Migrate the schema
db.AutoMigrate(&UserClient{})
db.AutoMigrate(&UserBanker{})
db.AutoMigrate(&BankAccount{})
db.AutoMigrate(&Operation{})
return &DataHandler{db: db}
}
// UserClient has many BankAccounts, UserClientID is the foreign key
type UserClient struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
Name string
BankAccounts []BankAccount
}
type UserBanker struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
Name string
UserClients []UserClient
}
// BankAccount belongs to an UserClient
type BankAccount struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
Number string `gorm:"primary_key"`
UserClientID uint
Type string
Amount int
BankOverdraft int
Operations []Operation `gorm:"foreignkey:Debtor"`
}
type Operation struct {
ID uint `gorm:"primary_key"`
Debtor uint
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
Amount int
Date time.Time
Creditor uint
}
// HandleClients expose the UserClients API
func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/"))
switch method := r.Method; method {
case "GET":
if id != 0 {
var o UserClient
if err := d.db.Preload("BankAccounts").First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []UserClient
d.db.Preload("BankAccounts").Find(&o)
json.NewEncoder(w).Encode(o)
}
case "POST":
var o UserClient
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
d.db.Create(&o)
case "DELETE":
if id != 0 {
var o UserClient
if err := d.db.First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
default:
http.Error(w, "method not allowed", 400)
}
}
func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/BankAccounts/"))
switch method := r.Method; method {
case "GET":
if id != 0 {
var o BankAccount
if err := d.db.Preload("Operations").First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []BankAccount
d.db.Preload("Operations").Find(&o)
json.NewEncoder(w).Encode(o)
}
case "POST":
var o BankAccount
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
d.db.Create(&o)
case "DELETE":
if id != 0 {
var o BankAccount
if err := d.db.First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
default:
http.Error(w, "method not allowed", 400)
}
}
func (d *DataHandler) HandleOperations(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/Operations/"))
switch method := r.Method; method {
case "GET":
if id != 0 {
var o Operation
if err := d.db.First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(o)
} else {
var o []Operation
d.db.Find(&o)
json.NewEncoder(w).Encode(o)
}
case "POST":
var o Operation
err := json.NewDecoder(r.Body).Decode(&o)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
var debtor BankAccount
var creditor BankAccount
if err := d.db.First(&debtor, o.Debtor).Error; err == nil {
if (debtor.Amount + o.Amount) >= debtor.BankOverdraft {
if err := d.db.First(&creditor, o.Creditor).Error; err == nil {
// Update BankAccounts
debtor.Amount += o.Amount
creditor.Amount -= o.Amount
d.db.Save(&debtor)
d.db.Save(&creditor)
now := time.Now()
o.Date = now
d.db.Create(&o)
// Add the operation to creditor
op := Operation{
Debtor: o.Creditor,
Amount: o.Amount,
Date: now,
Creditor: o.Debtor,
}
d.db.Create(&op)
}
} else {
http.Error(w, "Not enough money", http.StatusExpectationFailed)
}
}
case "DELETE":
if id != 0 {
var o Operation
if err := d.db.First(&o, id).Error; err != nil {
http.Error(w, "id does not exist", http.StatusNotFound)
return
}
d.db.Delete(&o)
} else {
http.Error(w, "id is missing", http.StatusNotFound)
}
default:
http.Error(w, "method not allowed", 400)
}
}
package models
import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"github.com/nicolaspernoud/vestibule/pkg/tester"
)
func TestHandleUserClients(t *testing.T) {
// Remove the test db to start clean
os.Remove("../../data/test.db")
// Create the handler
dh := NewDataHandler()
ts := httptest.NewServer(http.HandlerFunc(dh.HandleClients))
defer ts.Close()
url, _ := url.Parse(ts.URL)
port := url.Port()
// Wrap the testing function
do := tester.CreateServerTester(t, port, "sdk-go.io", nil)
noH := tester.Header{Key: "", Value: ""}
// Try to create a client
do("POST", "/api/UserClients", noH, `{"Name":"Dupond"}`, 200, "")
// Try to create an other one
do("POST", "/api/UserClients", noH, `{"Name":"Boulangerie"}`, 200, "")
// Try to get the first client
do("GET", "/api/UserClients/1", noH, "", 200, `{"ID":1,"Name":"Dupond","BankAccounts":[]}`)
// // Try to get all the clients
do("GET", "/api/UserClients", noH, "", 200, `[{"ID":1,"Name":"Dupond","BankAccounts":[]},{"ID":2,"Name":"Boulangerie","BankAccounts":[]}]`)
}
func TestHandleBankAccounts(t *testing.T) {
// Create the handler
dh := NewDataHandler()
ts := httptest.NewServer(http.HandlerFunc(dh.HandleBankAccounts))
defer ts.Close()
url, _ := url.Parse(ts.URL)
port := url.Port()
// Wrap the testing function
do := tester.CreateServerTester(t, port, "sdk-go.io", nil)
noH := tester.Header{Key: "", Value: ""}
// Add bank account to client
do("POST", "/api/BankAccounts", noH, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 200, "")
// Add an other bank account to client
do("POST", "/api/BankAccounts", noH, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 200, "")
// Get account where id=1
do("GET", "/api/BankAccounts/1", noH, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]}`)
// Get all Bank account
do("GET", "/api/BankAccounts/", noH, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":[]}]`)
// Add a bank account to Bakery
do("POST", "/api/BankAccounts", noH, `{"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500}`, 200, "")
// Try to delete both BankAccount
// do("DELETE", "/api/BankAccounts/1", noH, ``, 200, "")
// do("DELETE", "/api/BankAccounts/2", noH, ``, 200, "")
}
func TestHandleOperations(t *testing.T) {
// Create the handler
dh := NewDataHandler()
ts := httptest.NewServer(http.HandlerFunc(dh.HandleOperations))
defer ts.Close()
url, _ := url.Parse(ts.URL)
port := url.Port()
// Wrap the testing function
do := tester.CreateServerTester(t, port, "sdk-go.io", nil)
noH := tester.Header{Key: "", Value: ""}
// Add operation between client and Bakery
do("POST", "/api/Operations", noH, `{"Debtor":1,"Amount":-100,"Creditor":3}`, 200, "")
// Get operation where id=1
do("GET", "/api/Operations/1", noH, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`)
// Get all Bank account
do("GET", "/api/Operations/", noH, "", 200, `[{"ID":1,"Debtor":1,"Amount":-100`)
// Add invalid operation between client and Bakery must be refused with 417 (Expectation failed)
do("POST", "/api/Operations", noH, `{"Debtor":1,"Amount":-1789,"Creditor":3}`, 417, "Not enough money")
}
func TestHandleUserClientWithAccounts(t *testing.T) {
// Create the handler
dh := NewDataHandler()
ts := httptest.NewServer(http.HandlerFunc(dh.HandleClients))
defer ts.Close()
url, _ := url.Parse(ts.URL)
port := url.Port()
// Wrap the testing function
do := tester.CreateServerTester(t, port, "sdk-go.io", nil)
noH := tester.Header{Key: "", Value: ""}
// Get client Dupond with his banks accounts and operations up to date (-100€ on checking-account)
do("GET", "/api/UserClients/1", noH, "", 200, `{"ID":1,"Name":"Dupond","BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":null}]}`)
// Get client Bakery with his banks accounts and operations up to date (+100€ on checking-account)
do("GET", "/api/UserClients/2", noH, "", 200, `{"ID":2,"Name":"Boulangerie","BankAccounts":[{"ID":3,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4845,"BankOverdraft":-500,"Operations":null}]}`)
// // Try to delete the above created user
// do("DELETE", "/api/UserBanks/1", noH, ``, 200, "")
// // Try to get the first user again
// do("GET", "/api/UserBanks/1", noH, "", 404, `id does not exist`)
}
......@@ -4,6 +4,7 @@ import (
"net/http"
"os"
"github.com/nicolaspernoud/vestibule/internal/models"
"github.com/nicolaspernoud/vestibule/pkg/auth"
"github.com/nicolaspernoud/vestibule/pkg/middlewares"
......@@ -28,6 +29,14 @@ func CreateRootMux(port int, staticDir string) RootMux {
mainMux.Handle("/OAuth2Callback", m.HandleOAuth2Callback())
mainMux.HandleFunc("/Logout", m.HandleLogout)
mainMux.HandleFunc("/Login", m.HandleInMemoryLogin)
// Bank API endpoints
dh := models.NewDataHandler()
mainMux.HandleFunc("/api/UserClients/", dh.HandleClients)
mainMux.HandleFunc("/api/BankAccounts/", dh.HandleBankAccounts)
mainMux.HandleFunc("/api/Operations/", dh.HandleOperations)
// Common API endpoints
commonMux := http.NewServeMux()
mainMux.Handle("/api/common/WhoAmI", auth.ValidateAuthMiddleware(auth.WhoAmI(), []string{"*"}, false))
commonMux.HandleFunc("/Share", auth.GetShareToken)
......
The MIT License (MIT)
Copyright (c) 2014 Ryan Uber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
package glob
import "strings"
// The character which is treated like a glob
const GLOB = "*"
// Glob will test a string pattern, potentially containing globs, against a
// subject string. The result is a simple true/false, determining whether or
// not the glob pattern matched the subject text.
func Glob(pattern, subj string) bool {
// Empty pattern can only match empty subject
if pattern == "" {
return subj == pattern
}
// If the pattern _is_ a glob, it matches everything
if pattern == GLOB {
return true
}
parts := strings.Split(pattern, GLOB)
if len(parts) == 1 {
// No globs in pattern, so test for equality
return subj == pattern
}
leadingGlob := strings.HasPrefix(pattern, GLOB)
trailingGlob := strings.HasSuffix(pattern, GLOB)
end := len(parts) - 1
// Go over the leading parts and ensure they match.
for i := 0; i < end; i++ {
idx := strings.Index(subj, parts[i])
switch i {
case 0:
// Check the first section. Requires special handling.
if !leadingGlob && idx != 0 {
return false
}
default:
// Check that the middle parts match.
if idx < 0 {
return false
}
}
// Trim evaluated text from subj as we loop over the pattern.
subj = subj[idx+len(parts[i]):]
}
// Reached the last section. Requires special handling.
return trailingGlob || strings.HasSuffix(subj, parts[end])
}
package glob
import (
"strings"
"testing"
)
func testGlobMatch(t *testing.T, pattern, subj string) {
if !Glob(pattern, subj) {
t.Fatalf("%s should match %s", pattern, subj)
}
}
func testGlobNoMatch(t *testing.T, pattern, subj string) {
if Glob(pattern, subj) {
t.Fatalf("%s should not match %s", pattern, subj)
}
}
func TestEmptyPattern(t *testing.T) {
testGlobMatch(t, "", "")
testGlobNoMatch(t, "", "test")
}
func TestEmptySubject(t *testing.T) {
for _, pattern := range []string{
"",
"*",
"**",
"***",
"****************",
strings.Repeat("*", 1000000),
} {
testGlobMatch(t, pattern, "")
}
for _, pattern := range []string{
// No globs/non-glob characters
"test",
"*test*",
// Trailing characters
"*x",
"*****************x",
strings.Repeat("*", 1000000) + "x",
// Leading characters
"x*",
"x*****************",
"x" + strings.Repeat("*", 1000000),
// Mixed leading/trailing characters
"x*x",
"x****************x",
"x" + strings.Repeat("*", 1000000) + "x",
} {
testGlobNoMatch(t, pattern, "")
}
}
func TestPatternWithoutGlobs(t *testing.T) {
testGlobMatch(t, "test", "test")
}