From 1ae1cfa59609f929d0306a80b197531cffe6fb0a Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sun, 8 Sep 2024 22:55:30 -0400 Subject: [PATCH 01/26] Add modelstesting package to provide test doubles for db operations removed gorm sqlite driver because it requires cgo to be enabled replaced with glebarez/sqlite which is a fork of of the gorm sqlite driver that does not use cgo. --- backend/go.mod | 14 ++++++-- backend/go.sum | 32 +++++++++++++++---- backend/models/modelstesting/modelstesting.go | 19 +++++++++++ .../modelstesting/modelstesting_test.go | 10 ++++++ 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 backend/models/modelstesting/modelstesting.go create mode 100644 backend/models/modelstesting/modelstesting_test.go diff --git a/backend/go.mod b/backend/go.mod index f442b06b..6ea5b9fc 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -4,6 +4,7 @@ go 1.23 require ( github.com/brianvoe/gofakeit v3.18.0+incompatible + github.com/glebarez/sqlite v1.11.0 github.com/golang-jwt/jwt/v4 v4.0.0 github.com/google/uuid v1.4.0 github.com/gorilla/mux v1.8.1 @@ -12,11 +13,12 @@ require ( golang.org/x/crypto v0.17.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/postgres v1.5.4 - gorm.io/driver/sqlite v1.5.6 - gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde + gorm.io/gorm v1.25.7 ) require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.5.4 // indirect @@ -24,8 +26,14 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 30b4be98..0cac378f 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -4,8 +4,16 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -28,10 +36,13 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= @@ -45,6 +56,9 @@ golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -55,7 +69,13 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= -gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= -gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= diff --git a/backend/models/modelstesting/modelstesting.go b/backend/models/modelstesting/modelstesting.go new file mode 100644 index 00000000..c495bc2a --- /dev/null +++ b/backend/models/modelstesting/modelstesting.go @@ -0,0 +1,19 @@ +// package modelstesting provides support for the +package modelstesting + +import ( + "testing" + + "github.com/glebarez/sqlite" + "gorm.io/gorm" +) + +// NewFakeDB returns a sqlite db running in memory as a gorm.DB +func NewFakeDB(t *testing.T) *gorm.DB { + t.Helper() + db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) + if err != nil { + t.Fatalf("Failed to connect to the database: %v", err) + } + return db +} diff --git a/backend/models/modelstesting/modelstesting_test.go b/backend/models/modelstesting/modelstesting_test.go new file mode 100644 index 00000000..f94937eb --- /dev/null +++ b/backend/models/modelstesting/modelstesting_test.go @@ -0,0 +1,10 @@ +package modelstesting + +import "testing" + +func TestNewFakeDB(t *testing.T) { + db := NewFakeDB(t) + if db == nil { + t.Error("Failed to create fake db") + } +} From d36152fb33ce34232034085815d204920f62e803 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sun, 8 Sep 2024 22:57:45 -0400 Subject: [PATCH 02/26] Update feeutils tests to use new fake db for db operations --- .../handlers/bets/betutils/feeutils_test.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/backend/handlers/bets/betutils/feeutils_test.go b/backend/handlers/bets/betutils/feeutils_test.go index 2dff7278..000dff7a 100644 --- a/backend/handlers/bets/betutils/feeutils_test.go +++ b/backend/handlers/bets/betutils/feeutils_test.go @@ -2,19 +2,14 @@ package betutils import ( "socialpredict/models" + "socialpredict/models/modelstesting" "socialpredict/setup/setuptesting" "testing" "time" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" ) func TestGetUserInitialBetFee(t *testing.T) { - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to the database: %v", err) - } + db := modelstesting.NewFakeDB(t) if err := db.AutoMigrate(&models.Bet{}, &models.User{}); err != nil { t.Fatalf("Failed to migrate models: %v", err) } @@ -79,13 +74,12 @@ func TestGetTransactionFee(t *testing.T) { func TestGetSumBetFees(t *testing.T) { // Set up in-memory SQLite database - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to the database: %v", err) - } + db := modelstesting.NewFakeDB(t) // Migrate the Bet model - db.AutoMigrate(&models.Bet{}) + if err := db.AutoMigrate(&models.Bet{}); err != nil { + t.Fatalf("Failed to auto migrate bets model %v", err) + } // Mock the appConfig with test data appConfig = setuptesting.MockEconomicConfig() From c68bd98b900daa9eaa646878b7987a4c9484a429 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sun, 8 Sep 2024 22:58:24 -0400 Subject: [PATCH 03/26] Update getbets tests to use new db fake --- backend/handlers/tradingdata/getbets_test.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/backend/handlers/tradingdata/getbets_test.go b/backend/handlers/tradingdata/getbets_test.go index 9073ad9b..0c7f091c 100644 --- a/backend/handlers/tradingdata/getbets_test.go +++ b/backend/handlers/tradingdata/getbets_test.go @@ -2,19 +2,14 @@ package tradingdata import ( "socialpredict/models" + "socialpredict/models/modelstesting" "testing" "time" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" ) func TestGetBetsForMarket(t *testing.T) { // Set up in-memory SQLite database - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - if err != nil { - t.Fatalf("Failed to connect to the database: %v", err) - } + db := modelstesting.NewFakeDB(t) // Auto-migrate the Bet model if err := db.AutoMigrate(&models.Bet{}); err != nil { From e17320b92264597fd1e5928ecb926ca5f92237a5 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:09:32 -0400 Subject: [PATCH 04/26] Update dependency versions to fix migration error with postgres driver version. Update migration errors and comments --- backend/go.mod | 37 ++++++------- backend/go.sum | 101 +++++++++++++++++++++-------------- backend/migration/migrate.go | 8 +-- 3 files changed, 84 insertions(+), 62 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index 6ea5b9fc..28bf7c87 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,35 +5,36 @@ go 1.23 require ( github.com/brianvoe/gofakeit v3.18.0+incompatible github.com/glebarez/sqlite v1.11.0 - github.com/golang-jwt/jwt/v4 v4.0.0 - github.com/google/uuid v1.4.0 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/joho/godotenv v1.5.1 github.com/rs/cors v1.11.1 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.27.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/postgres v1.5.4 - gorm.io/gorm v1.25.7 + gorm.io/driver/postgres v1.5.9 + gorm.io/gorm v1.25.12 ) require ( github.com/dustin/go-humanize v1.0.1 // indirect - github.com/glebarez/go-sqlite v1.21.2 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.5.4 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - modernc.org/libc v1.22.5 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/sqlite v1.23.1 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + modernc.org/libc v1.60.1 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.33.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 0cac378f..4c6c5dc1 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -6,26 +6,26 @@ 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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= -github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= -github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= -github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 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.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -36,15 +36,16 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -52,30 +53,50 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= -gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= -gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= -gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= -modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= +gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= +gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.21.0 h1:kKPI3dF7RIag8YcToh5ZwDcVMIv6VGa0ED5cvh0LMW4= +modernc.org/ccgo/v4 v4.21.0/go.mod h1:h6kt6H/A2+ew/3MW/p6KEoQmrq/i3pr0J/SiwiaF/g0= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= +modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/libc v1.60.1 h1:at373l8IFRTkJIkAU85BIuUoBM4T1b51ds0E1ovPG2s= +modernc.org/libc v1.60.1/go.mod h1:xJuobKuNxKH3RUatS7GjR+suWj+5c2K7bi4m/S5arOY= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= +modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/backend/migration/migrate.go b/backend/migration/migrate.go index 1d1abccc..5a372849 100644 --- a/backend/migration/migrate.go +++ b/backend/migration/migrate.go @@ -8,16 +8,16 @@ import ( ) func MigrateDB(db *gorm.DB) { - // Migrate the User and Market models first + // Migrate the User modelsfirst err := db.AutoMigrate(&models.User{}) if err != nil { - log.Fatalf("Error migrating User and Market models: %v", err) + log.Fatalf("Error migrating User model: %v", err) } - // Then, migrate the Bet model + // Then, migrate the Market model err = db.AutoMigrate(&models.Market{}) if err != nil { - log.Fatalf("Error migrating Bet model: %v", err) + log.Fatalf("Error migrating Market model: %v", err) } // Then, migrate the Bet model From 7d196291eeca5ffc72669185c75c2ad8baa4d113 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Fri, 13 Sep 2024 01:08:42 -0400 Subject: [PATCH 05/26] Update broken dependency and add FakeDB initialization testing --- backend/go.mod | 2 +- backend/go.sum | 2 ++ backend/models/modelstesting/modelstesting.go | 3 ++ .../modelstesting/modelstesting_test.go | 34 ++++++++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index 28bf7c87..6acbc87d 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -36,5 +36,5 @@ require ( modernc.org/libc v1.60.1 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.33.0 // indirect + modernc.org/sqlite v1.33.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 4c6c5dc1..13e17c0f 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -96,6 +96,8 @@ modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= +modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= +modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/backend/models/modelstesting/modelstesting.go b/backend/models/modelstesting/modelstesting.go index c495bc2a..b1e99090 100644 --- a/backend/models/modelstesting/modelstesting.go +++ b/backend/models/modelstesting/modelstesting.go @@ -4,6 +4,8 @@ package modelstesting import ( "testing" + "socialpredict/migration" + "github.com/glebarez/sqlite" "gorm.io/gorm" ) @@ -15,5 +17,6 @@ func NewFakeDB(t *testing.T) *gorm.DB { if err != nil { t.Fatalf("Failed to connect to the database: %v", err) } + migration.MigrateDB(db) return db } diff --git a/backend/models/modelstesting/modelstesting_test.go b/backend/models/modelstesting/modelstesting_test.go index f94937eb..05e552a7 100644 --- a/backend/models/modelstesting/modelstesting_test.go +++ b/backend/models/modelstesting/modelstesting_test.go @@ -1,10 +1,42 @@ package modelstesting -import "testing" +import ( + "socialpredict/models" + "testing" +) func TestNewFakeDB(t *testing.T) { db := NewFakeDB(t) if db == nil { t.Error("Failed to create fake db") } + tests := []struct { + Name string + Table interface{} + WantRows int + }{ + { + Name: "QueryUsers0", + Table: &models.User{}, + WantRows: 0, + }, + { + Name: "QueryMarkets0", + Table: &models.Market{}, + WantRows: 0, + }, + { + Name: "QueryBets0", + Table: &models.Bet{}, + WantRows: 0, + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + result := db.Find(test.Table) + if int(result.RowsAffected) != test.WantRows { + t.Fail() + } + }) + } } From b756c4a371f342ad9e5678b1099516436961e8a5 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Fri, 13 Sep 2024 01:10:11 -0400 Subject: [PATCH 06/26] Update test to fail immediately if the db doesn't start --- backend/models/modelstesting/modelstesting_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/models/modelstesting/modelstesting_test.go b/backend/models/modelstesting/modelstesting_test.go index 05e552a7..c910923e 100644 --- a/backend/models/modelstesting/modelstesting_test.go +++ b/backend/models/modelstesting/modelstesting_test.go @@ -8,7 +8,7 @@ import ( func TestNewFakeDB(t *testing.T) { db := NewFakeDB(t) if db == nil { - t.Error("Failed to create fake db") + t.Fatal("Failed to create fake db") } tests := []struct { Name string From 86be18415a14405ab32968480efa18232e931332 Mon Sep 17 00:00:00 2001 From: Arthur <25300182+ajlacey@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:12:02 -0400 Subject: [PATCH 07/26] Update add user handler to use DI (#307) --- backend/handlers/admin/adduser.go | 136 ++++++++++++++---------------- backend/server/server.go | 2 +- 2 files changed, 63 insertions(+), 75 deletions(-) diff --git a/backend/handlers/admin/adduser.go b/backend/handlers/admin/adduser.go index 93faa199..3b56772b 100644 --- a/backend/handlers/admin/adduser.go +++ b/backend/handlers/admin/adduser.go @@ -3,7 +3,6 @@ package adminhandlers import ( "encoding/json" "fmt" - "log" "math/rand" "net/http" "regexp" @@ -16,81 +15,70 @@ import ( "gorm.io/gorm" ) -// appConfig holds the loaded application configuration accessible within the package -var appConfig *setup.EconomicConfig - -func init() { - var err error - appConfig, err = setup.LoadEconomicsConfig() - if err != nil { - log.Fatalf("Failed to load configuration: %v", err) +func AddUserHandler(loadEconConfig setup.EconConfigLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not supported", http.StatusMethodNotAllowed) + return + } + + var req struct { + Username string `json:"username"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "Error decoding request body", http.StatusBadRequest) + return + } + + if match, _ := regexp.MatchString("^[a-zA-Z0-9]+$", req.Username); !match { + http.Error(w, "Username must only contain letters and numbers", http.StatusBadRequest) + return + } + + db := util.GetDB() + + // validate that the user performing this function is indeed admin + middleware.ValidateAdminToken(r, db) + + appConfig := loadEconConfig() + user := models.User{ + Username: req.Username, + DisplayName: util.UniqueDisplayName(db), + Email: util.UniqueEmail(db), + UserType: "REGULAR", + InitialAccountBalance: appConfig.Economics.User.InitialAccountBalance, + AccountBalance: appConfig.Economics.User.InitialAccountBalance, + PersonalEmoji: randomEmoji(), + ApiKey: util.GenerateUniqueApiKey(db), + MustChangePassword: true, + } + + // Check uniqueness of username, displayname, and email + if err := checkUniqueFields(db, &user); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + password := gofakeit.Password(true, true, true, false, false, 12) + if err := user.HashPassword(password); err != nil { + http.Error(w, "Failed to hash password", http.StatusInternalServerError) + return + } + + if result := db.Create(&user); result.Error != nil { + http.Error(w, "Failed to create user", http.StatusInternalServerError) + return + } + + responseData := map[string]interface{}{ + "message": "User created successfully", + "username": user.Username, + "password": password, + "usertype": user.UserType, + } + json.NewEncoder(w).Encode(responseData) } } - -func AddUserHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "Method not supported", http.StatusMethodNotAllowed) - return - } - - var req struct { - Username string `json:"username"` - } - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, "Error decoding request body", http.StatusBadRequest) - return - } - - if match, _ := regexp.MatchString("^[a-zA-Z0-9]+$", req.Username); !match { - http.Error(w, "Username must only contain letters and numbers", http.StatusBadRequest) - return - } - - db := util.GetDB() - - // validate that the user performing this function is indeed admin - middleware.ValidateAdminToken(r, db) - - var user models.User - - user = models.User{ - Username: req.Username, - DisplayName: util.UniqueDisplayName(db), - Email: util.UniqueEmail(db), - UserType: "REGULAR", - InitialAccountBalance: appConfig.Economics.User.InitialAccountBalance, - AccountBalance: appConfig.Economics.User.InitialAccountBalance, - PersonalEmoji: randomEmoji(), - ApiKey: util.GenerateUniqueApiKey(db), - MustChangePassword: true, - } - - // Check uniqueness of username, displayname, and email - if err := checkUniqueFields(db, &user); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - password := gofakeit.Password(true, true, true, false, false, 12) - if err := user.HashPassword(password); err != nil { - http.Error(w, "Failed to hash password", http.StatusInternalServerError) - return - } - - if result := db.Create(&user); result.Error != nil { - http.Error(w, "Failed to create user", http.StatusInternalServerError) - return - } - - responseData := map[string]interface{}{ - "message": "User created successfully", - "username": user.Username, - "password": password, - "usertype": user.UserType, - } - json.NewEncoder(w).Encode(responseData) -} - func checkUniqueFields(db *gorm.DB, user *models.User) error { // Check for existing users with the same username, display name, email, or API key. var count int64 diff --git a/backend/server/server.go b/backend/server/server.go index e9f9a2d9..c3293a3f 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -74,7 +74,7 @@ func Start() { router.HandleFunc("/v0/create", marketshandlers.CreateMarketHandler).Methods("POST") // admin stuff - router.HandleFunc("/v0/admin/createuser", adminhandlers.AddUserHandler).Methods("POST") + router.HandleFunc("/v0/admin/createuser", adminhandlers.AddUserHandler(setup.EconomicsConfig)).Methods("POST") // Apply the CORS middleware to the Gorilla Mux router handler := c.Handler(router) // Use the Gorilla Mux router here From 93e9a5a73744367793a130f8b63fdf6b3a2798bb Mon Sep 17 00:00:00 2001 From: Arthur <25300182+ajlacey@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:13:15 -0400 Subject: [PATCH 08/26] Update Create Market Handler to use EconConfigLoader (#310) --- backend/handlers/markets/createmarket.go | 150 +++++++++++------------ backend/server/server.go | 2 +- 2 files changed, 72 insertions(+), 80 deletions(-) diff --git a/backend/handlers/markets/createmarket.go b/backend/handlers/markets/createmarket.go index eca38fdd..167eb42c 100644 --- a/backend/handlers/markets/createmarket.go +++ b/backend/handlers/markets/createmarket.go @@ -16,18 +16,6 @@ import ( const maxQuestionTitleLength = 160 -// appConfig holds the loaded application configuration accessible within the package -var appConfig *setup.EconomicConfig - -func init() { - // Load configuration - var err error - appConfig, err = setup.LoadEconomicsConfig() - if err != nil { - log.Fatalf("Failed to load configuration: %v", err) - } -} - func checkQuestionTitleLength(title string) error { if len(title) > maxQuestionTitleLength || len(title) < 1 { return fmt.Errorf("question title exceeds %d characters or is blank", maxQuestionTitleLength) @@ -37,90 +25,94 @@ func checkQuestionTitleLength(title string) error { func checkQuestionDescriptionLength(description string) error { if len(description) > 2000 { - return errors.New("Question Description exceeds 2000 characters") + return errors.New("question description exceeds 2000 characters") } return nil } -func CreateMarketHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed) - return - } +func CreateMarketHandler(loadEconConfig setup.EconConfigLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed) + return + } - // Use database connection, validate user based upon token - db := util.GetDB() - user, httperr := middleware.ValidateUserAndEnforcePasswordChangeGetUser(r, db) - if httperr != nil { - http.Error(w, httperr.Error(), httperr.StatusCode) - return - } + // Use database connection, validate user based upon token + db := util.GetDB() + user, httperr := middleware.ValidateUserAndEnforcePasswordChangeGetUser(r, db) + if httperr != nil { + http.Error(w, httperr.Error(), httperr.StatusCode) + return + } - var newMarket models.Market + var newMarket models.Market - newMarket.CreatorUsername = user.Username + newMarket.CreatorUsername = user.Username - err := json.NewDecoder(r.Body).Decode(&newMarket) - if err != nil { - bodyBytes, _ := io.ReadAll(r.Body) - log.Printf("Error reading request body: %v, Body: %s", err, string(bodyBytes)) - http.Error(w, "Error reading request body", http.StatusBadRequest) - return - } + err := json.NewDecoder(r.Body).Decode(&newMarket) + if err != nil { + bodyBytes, _ := io.ReadAll(r.Body) + log.Printf("Error reading request body: %v, Body: %s", err, string(bodyBytes)) + http.Error(w, "Error reading request body", http.StatusBadRequest) + return + } - if err = checkQuestionTitleLength(newMarket.QuestionTitle); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } + if err = checkQuestionTitleLength(newMarket.QuestionTitle); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - if err = checkQuestionDescriptionLength(newMarket.Description); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } + if err = checkQuestionDescriptionLength(newMarket.Description); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - if err = util.CheckUserIsReal(db, newMarket.CreatorUsername); err != nil { - if err.Error() == "creator user not found" { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + if err = util.CheckUserIsReal(db, newMarket.CreatorUsername); err != nil { + if err.Error() == "creator user not found" { + http.Error(w, err.Error(), http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return } - return - } - // Subtract any Market Creation Fees from Creator, up to maximum debt - marketCreateFee := appConfig.Economics.MarketIncentives.CreateMarketCost - maximumDebtAllowed := appConfig.Economics.User.MaximumDebtAllowed + appConfig := loadEconConfig() - // Maximum debt allowed check - if user.AccountBalance-marketCreateFee < -maximumDebtAllowed { - http.Error(w, "Insufficient balance", http.StatusBadRequest) - return - } + // Subtract any Market Creation Fees from Creator, up to maximum debt + marketCreateFee := appConfig.Economics.MarketIncentives.CreateMarketCost + maximumDebtAllowed := appConfig.Economics.User.MaximumDebtAllowed - // deduct fee - logging.LogAnyType(user.AccountBalance, "user.AccountBalance before") - // Deduct the bet and switching sides fee amount from the user's balance - user.AccountBalance -= marketCreateFee - logging.LogAnyType(user.AccountBalance, "user.AccountBalance after") + // Maximum debt allowed check + if user.AccountBalance-marketCreateFee < -maximumDebtAllowed { + http.Error(w, "Insufficient balance", http.StatusBadRequest) + return + } - // Update the user's balance in the database - if err := db.Save(&user).Error; err != nil { - http.Error(w, "Error updating user balance: "+err.Error(), http.StatusInternalServerError) - return - } + // deduct fee + logging.LogAnyType(user.AccountBalance, "user.AccountBalance before") + // Deduct the bet and switching sides fee amount from the user's balance + user.AccountBalance -= marketCreateFee + logging.LogAnyType(user.AccountBalance, "user.AccountBalance after") - // Create the market in the database - result := db.Create(&newMarket) - if result.Error != nil { - log.Printf("Error creating new market: %v", result.Error) - http.Error(w, "Error creating new market", http.StatusInternalServerError) - return - } + // Update the user's balance in the database + if err := db.Save(&user).Error; err != nil { + http.Error(w, "Error updating user balance: "+err.Error(), http.StatusInternalServerError) + return + } - // Set the Content-Type header - w.Header().Set("Content-Type", "application/json") + // Create the market in the database + result := db.Create(&newMarket) + if result.Error != nil { + log.Printf("Error creating new market: %v", result.Error) + http.Error(w, "Error creating new market", http.StatusInternalServerError) + return + } - // Send a success response - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(newMarket) + // Set the Content-Type header + w.Header().Set("Content-Type", "application/json") + + // Send a success response + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(newMarket) + } } diff --git a/backend/server/server.go b/backend/server/server.go index c3293a3f..922e37c4 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -71,7 +71,7 @@ func Start() { router.HandleFunc("/v0/bet", betshandlers.PlaceBetHandler).Methods("POST") router.HandleFunc("/v0/userposition/{marketId}", usershandlers.UserMarketPositionHandler) router.HandleFunc("/v0/sell", betshandlers.SellPositionHandler).Methods("POST") - router.HandleFunc("/v0/create", marketshandlers.CreateMarketHandler).Methods("POST") + router.HandleFunc("/v0/create", marketshandlers.CreateMarketHandler(setup.EconomicsConfig)).Methods("POST") // admin stuff router.HandleFunc("/v0/admin/createuser", adminhandlers.AddUserHandler(setup.EconomicsConfig)).Methods("POST") From 8abb0e4d85efbaab6ff06276517a85b1c2d7c403 Mon Sep 17 00:00:00 2001 From: Patrick Delaney Date: Mon, 9 Sep 2024 12:31:56 -0500 Subject: [PATCH 09/26] Create CONTRIBUTING.md (#312) --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..296351ff --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contributing to SocialPredict + +We welcome contributions from the community and are pleased that you're interested in participating in the development of SocialPredict. Here are the guidelines we'd like you to follow: + +## How to Contribute + +1. **Fork the Repository** + - Start by forking the SocialPredict repository to your GitHub account. + +2. **Clone Your Fork** + - Clone your fork to your local machine to start making changes. + +3. **Create a Branch** + - Create a new branch in your local repository before starting your work. + - Use a clear branch name that describes the intent of your work, such as `feature/add-login` or `fix/header-bug`. + +4. **Commit Your Changes** + - Keep your commits as atomic as possible, each addressing a single concern. + - Use clear and descriptive commit messages. + +5. **Push Your Changes** + - Push your changes to your fork on GitHub. + +6. **Submit a Pull Request** + - Open a pull request to the main SocialPredict repository. + - Provide a concise description of the changes and the reasoning behind them. + +## Reporting Issues + +If you find a bug or have a feature request, please use the GitHub Issues tab to report them. Before creating a new issue, check to ensure the issue hasn't already been reported. When filing an issue, please include: + +- A clear title and description. +- As much relevant information as possible. +- A code sample or an executable test case demonstrating the expected behavior that is not occurring. + +## Conduct + +We are committed to providing a welcoming and inspiring community for all. Please take a moment to read our Code of Conduct before participating. + +## Questions? + +If you have any questions, please feel free to ask them on our Github discussions page or reach out directly via GitHub issues. + +Thank you for contributing to SocialPredict! From 497bb921ea6cd74fdb38f4bf2c5b8c6fd549d7a7 Mon Sep 17 00:00:00 2001 From: Patrick Delaney Date: Mon, 9 Sep 2024 12:33:34 -0500 Subject: [PATCH 10/26] Update issue templates (#313) Bug report template updated --- .github/ISSUE_TEMPLATE/bug_report.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dd84ea78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. From 96e25acc64981f1bdca88196ad8cc165aad550b7 Mon Sep 17 00:00:00 2001 From: Arthur <25300182+ajlacey@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:46:19 -0400 Subject: [PATCH 11/26] Update gitignore to include backend test coverage html output (#316) When running the below commands, a *.out and cover.html file are generated. We may want to make these patterns more generic, but for now this will prevent them from being tracked in the backend. go test -coverprofile=c.out ./... go tool cover -html=c.out -o=cover.html --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 157f059c..ef3e2b9f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,9 @@ # Test binary, built with `go test -c` *.test -# Output of the go coverage tool, specifically when used with LiteIDE +# Output of the go coverage tool *.out +backend/**/cover.html # Dependency directories (remove the comment below to include it) # vendor/ From e276a86669e3ad5daf08219cf8863441c8f32406 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:26:41 -0400 Subject: [PATCH 12/26] Add MarketCreationLoader interface and make EconomicConfig and MarketCreation types implement the interface --- backend/setup/setup.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/setup/setup.go b/backend/setup/setup.go index d4b283b0..ba906152 100644 --- a/backend/setup/setup.go +++ b/backend/setup/setup.go @@ -70,11 +70,24 @@ func LoadEconomicsConfig() (*EconomicConfig, error) { // EconConfigLoader allows functions to use this type as a parameter to load an EconomicConfig Dependency type EconConfigLoader func() *EconomicConfig +// MarketCreationLoader loads just the market creation component of the setup +type MarketCreationLoader interface { + LoadMarketCreation() MarketCreation +} + // EconomicsConfig returns the entire config for the applications economics func EconomicsConfig() *EconomicConfig { return economicConfig } +func (ec *EconomicConfig) LoadMarketCreation() MarketCreation { + return ec.Economics.MarketCreation +} + +func (mc *MarketCreation) LoadMarketCreation() MarketCreation { + return *mc +} + func mustLoadEconomicsConfig() { economicConfig = &EconomicConfig{} err := yaml.Unmarshal(setupYaml, economicConfig) From a6cdd33fd0123f5489719b76481ab29c38b0626a Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:28:41 -0400 Subject: [PATCH 13/26] Add argument to CalculateMarketProbabilitiesWPAM signature --- .../wpam/wpam_marketprobabilities.go | 28 +-- .../wpam/wpam_marketprobabilities_test.go | 218 +++++++----------- 2 files changed, 91 insertions(+), 155 deletions(-) diff --git a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go index 1a5877d6..9ceef13d 100644 --- a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go +++ b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go @@ -1,7 +1,6 @@ package wpam import ( - "log" "socialpredict/models" "socialpredict/setup" "time" @@ -16,27 +15,16 @@ type ProjectedProbability struct { Probability float64 `json:"projectedprobability"` } -// appConfig holds the loaded application configuration accessible within the package -var appConfig *setup.EconomicConfig - -func init() { - // Load configuration - var err error - appConfig, err = setup.LoadEconomicsConfig() - if err != nil { - log.Fatalf("Failed to load configuration: %v", err) - } -} - // CalculateMarketProbabilitiesWPAM calculates and returns the probability changes based on bets. -func CalculateMarketProbabilitiesWPAM(marketCreatedAtTime time.Time, bets []models.Bet) []ProbabilityChange { +func CalculateMarketProbabilitiesWPAM(mcl setup.MarketCreationLoader, marketCreatedAtTime time.Time, bets []models.Bet) []ProbabilityChange { var probabilityChanges []ProbabilityChange + mc := mcl.LoadMarketCreation() // Initial state using values from appConfig - P_initial := appConfig.Economics.MarketCreation.InitialMarketProbability - I_initial := appConfig.Economics.MarketCreation.InitialMarketSubsidization - totalYes := appConfig.Economics.MarketCreation.InitialMarketYes - totalNo := appConfig.Economics.MarketCreation.InitialMarketNo + P_initial := mc.InitialMarketProbability + I_initial := mc.InitialMarketSubsidization + totalYes := mc.InitialMarketYes + totalNo := mc.InitialMarketNo probabilityChanges = append(probabilityChanges, ProbabilityChange{Probability: P_initial, Timestamp: marketCreatedAtTime}) @@ -55,11 +43,11 @@ func CalculateMarketProbabilitiesWPAM(marketCreatedAtTime time.Time, bets []mode return probabilityChanges } -func ProjectNewProbabilityWPAM(marketCreatedAtTime time.Time, currentBets []models.Bet, newBet models.Bet) ProjectedProbability { +func ProjectNewProbabilityWPAM(mcl setup.MarketCreationLoader, marketCreatedAtTime time.Time, currentBets []models.Bet, newBet models.Bet) ProjectedProbability { updatedBets := append(currentBets, newBet) - probabilityChanges := CalculateMarketProbabilitiesWPAM(marketCreatedAtTime, updatedBets) + probabilityChanges := CalculateMarketProbabilitiesWPAM(mcl, marketCreatedAtTime, updatedBets) finalProbability := probabilityChanges[len(probabilityChanges)-1].Probability diff --git a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities_test.go b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities_test.go index b67e99e6..6c6b8629 100644 --- a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities_test.go +++ b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities_test.go @@ -1,155 +1,103 @@ -package wpam_test +package wpam import ( "fmt" - "socialpredict/handlers/math/outcomes/dbpm" - "socialpredict/handlers/math/probabilities/wpam" "socialpredict/models" + "socialpredict/setup" + "socialpredict/setup/setuptesting" "testing" "time" ) -type TestCase struct { - Name string - Bets []models.Bet - ProbabilityChanges []wpam.ProbabilityChange - S_YES int64 - S_NO int64 - CoursePayouts []dbpm.CourseBetPayout - F_YES float64 - F_NO float64 - ExpectedF_YES float64 - ExpectedF_NO float64 - ScaledPayouts []int64 - AdjustedScaledPayouts []int64 - AggregatedPositions []dbpm.MarketPosition - NetPositions []dbpm.MarketPosition -} - var now = time.Now() // Capture current time for consistent test data -var TestCases = []TestCase{ - { - Name: "Prevent simultaneous shares held", - Bets: []models.Bet{ - { - Amount: 3, - Outcome: "YES", - Username: "user1", - PlacedAt: time.Date(2024, 5, 18, 5, 7, 31, 428975000, time.UTC), - MarketID: 3, +func TestCalculateMarketProbabilitiesWPAM(t *testing.T) { + testcases := []struct { + Name string + Bets models.Bets + ProbabilityChanges []ProbabilityChange + MarketCreationConfig setup.MarketCreationLoader + }{ + { + Name: "PreventSimultaneousSharesHeld", + Bets: []models.Bet{ + { + Amount: 3, + Outcome: "YES", + Username: "user1", + PlacedAt: time.Date(2024, 5, 18, 5, 7, 31, 428975000, time.UTC), + MarketID: 3, + }, + { + Amount: 1, + Outcome: "NO", + Username: "user1", + PlacedAt: time.Date(2024, 5, 18, 5, 8, 13, 922665000, time.UTC), + MarketID: 3, + }, }, - { - Amount: 1, - Outcome: "NO", - Username: "user1", - PlacedAt: time.Date(2024, 5, 18, 5, 8, 13, 922665000, time.UTC), - MarketID: 3, + ProbabilityChanges: []ProbabilityChange{ + {Probability: 0.5}, + {Probability: 0.875}, + {Probability: 0.7}, }, + MarketCreationConfig: setuptesting.BuildInitialMarketAppConfig(t, .5, 1, 0, 0), }, - ProbabilityChanges: []wpam.ProbabilityChange{ - {Probability: 0.5}, - {Probability: 0.61538461538461542}, - {Probability: 0.57142857142857140}, - }, - S_YES: 3, - S_NO: 1, - CoursePayouts: []dbpm.CourseBetPayout{ - {Payout: 0.5999999999999999, Outcome: "YES"}, - {Payout: 0.17500000000000004, Outcome: "NO"}, - }, - F_YES: 5.000000000000001, - F_NO: 5.714285714285713, - ExpectedF_YES: 5.000000, - ExpectedF_NO: 5.714286, - ScaledPayouts: []int64{3, 1}, - AdjustedScaledPayouts: []int64{3, 1}, - AggregatedPositions: []dbpm.MarketPosition{ - {Username: "user1", YesSharesOwned: 3, NoSharesOwned: 1}, - }, - NetPositions: []dbpm.MarketPosition{ - {Username: "user1", YesSharesOwned: 2, NoSharesOwned: 0}, - }, - }, - { - Name: "infinity avoidance", - Bets: []models.Bet{ - { - Amount: 1, - Outcome: "YES", - Username: "user2", - PlacedAt: now, - MarketID: 1, - }, - { - Amount: -1, - Outcome: "YES", - Username: "user2", - PlacedAt: now.Add(time.Minute), - MarketID: 1, - }, - { - Amount: 1, - Outcome: "NO", - Username: "user1", - PlacedAt: now.Add(2 * time.Minute), - MarketID: 1, + { + Name: "InfinityAvoidance", + Bets: []models.Bet{ + { + Amount: 1, + Outcome: "YES", + Username: "user2", + PlacedAt: now, + MarketID: 1, + }, + { + Amount: -1, + Outcome: "YES", + Username: "user2", + PlacedAt: now.Add(time.Minute), + MarketID: 1, + }, + { + Amount: 1, + Outcome: "NO", + Username: "user1", + PlacedAt: now.Add(2 * time.Minute), + MarketID: 1, + }, + { + Amount: -1, + Outcome: "NO", + Username: "user1", + PlacedAt: now.Add(3 * time.Minute), + MarketID: 1, + }, + { + Amount: 1, + Outcome: "NO", + Username: "user1", + PlacedAt: now.Add(4 * time.Minute), + MarketID: 1, + }, }, - { - Amount: -1, - Outcome: "NO", - Username: "user1", - PlacedAt: now.Add(3 * time.Minute), - MarketID: 1, + ProbabilityChanges: []ProbabilityChange{ + {Probability: 0.50}, + {Probability: 0.75}, + {Probability: 0.50}, + {Probability: 0.25}, + {Probability: 0.50}, + {Probability: 0.25}, }, - { - Amount: 1, - Outcome: "NO", - Username: "user1", - PlacedAt: now.Add(4 * time.Minute), - MarketID: 1, - }, - }, - ProbabilityChanges: []wpam.ProbabilityChange{ - {Probability: 0.50}, - {Probability: 0.54545454545454541}, - {Probability: 0.50}, - {Probability: 0.45454545454545453}, - {Probability: 0.50}, - {Probability: 0.45454545454545453}, - }, - S_YES: 0, - S_NO: 1, - CoursePayouts: []dbpm.CourseBetPayout{ - {Payout: 0.25, Outcome: "YES"}, - {Payout: -0.5, Outcome: "YES"}, - {Payout: 0.25, Outcome: "NO"}, - {Payout: -0, Outcome: "NO"}, // golang math.Round() rounds to -0 and +0 - {Payout: 0.25, Outcome: "NO"}, - }, - F_YES: 0, - F_NO: 2, - ExpectedF_YES: 0, - ExpectedF_NO: 2, - ScaledPayouts: []int64{0, 0, 1, 0, 1}, - AdjustedScaledPayouts: []int64{0, 0, 1, 0, 0}, - AggregatedPositions: []dbpm.MarketPosition{ - {Username: "user1", YesSharesOwned: 0, NoSharesOwned: 1}, - {Username: "user2", YesSharesOwned: 0, NoSharesOwned: 0}, - }, - NetPositions: []dbpm.MarketPosition{ - {Username: "user1", YesSharesOwned: 0, NoSharesOwned: 1}, - {Username: "user2", YesSharesOwned: 0, NoSharesOwned: 0}, + MarketCreationConfig: setuptesting.BuildInitialMarketAppConfig(t, .5, 1, 0, 0), }, - }, -} - -func TestCalculateMarketProbabilitiesWPAM(t *testing.T) { - for _, tc := range TestCases { + } + for _, tc := range testcases { t.Run(tc.Name, func(t *testing.T) { // Call the function under test - probChanges := wpam.CalculateMarketProbabilitiesWPAM(tc.Bets[0].PlacedAt, tc.Bets) + probChanges := CalculateMarketProbabilitiesWPAM(tc.MarketCreationConfig, tc.Bets[0].PlacedAt, tc.Bets) if len(probChanges) != len(tc.ProbabilityChanges) { t.Fatalf("expected %d probability changes, got %d", len(tc.ProbabilityChanges), len(probChanges)) @@ -158,10 +106,10 @@ func TestCalculateMarketProbabilitiesWPAM(t *testing.T) { for i, pc := range probChanges { expected := tc.ProbabilityChanges[i] - fmt.Printf("at index %d, expected probability %.17f, got %.17f\n", i, expected.Probability, pc.Probability) + fmt.Printf("at index %d, expected probability %f, got %f\n", i, expected.Probability, pc.Probability) if pc.Probability != expected.Probability { - t.Errorf("at index %d, expected probability %.17f, got %.17f", i, expected.Probability, pc.Probability) + t.Errorf("at index %d, expected probability %f, got %f", i, expected.Probability, pc.Probability) } } From 0fa7e43596d5e6be64e2731098465635ca32cdf7 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:34:58 -0400 Subject: [PATCH 14/26] fix spacing --- .../math/probabilities/wpam/wpam_marketprobabilities.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go index 9ceef13d..a2617c54 100644 --- a/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go +++ b/backend/handlers/math/probabilities/wpam/wpam_marketprobabilities.go @@ -44,11 +44,8 @@ func CalculateMarketProbabilitiesWPAM(mcl setup.MarketCreationLoader, marketCrea } func ProjectNewProbabilityWPAM(mcl setup.MarketCreationLoader, marketCreatedAtTime time.Time, currentBets []models.Bet, newBet models.Bet) ProjectedProbability { - updatedBets := append(currentBets, newBet) - probabilityChanges := CalculateMarketProbabilitiesWPAM(mcl, marketCreatedAtTime, updatedBets) - finalProbability := probabilityChanges[len(probabilityChanges)-1].Probability return ProjectedProbability{Probability: finalProbability} From b8e5b7f95a36f4c7f3c87af48a12053286f4a033 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:05:20 -0400 Subject: [PATCH 15/26] Update positionsmath to use a market creation loader, and add an empty test --- backend/handlers/positions/positionsmath.go | 17 +++++------ .../handlers/positions/positionsmath_test.go | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 backend/handlers/positions/positionsmath_test.go diff --git a/backend/handlers/positions/positionsmath.go b/backend/handlers/positions/positionsmath.go index f28b0f61..baf2c204 100644 --- a/backend/handlers/positions/positionsmath.go +++ b/backend/handlers/positions/positionsmath.go @@ -6,7 +6,7 @@ import ( "socialpredict/handlers/math/outcomes/dbpm" "socialpredict/handlers/math/probabilities/wpam" "socialpredict/handlers/tradingdata" - "socialpredict/models" + "socialpredict/setup" "strconv" "gorm.io/gorm" @@ -27,7 +27,7 @@ type UserMarketPosition struct { // FetchMarketPositions fetches and summarizes positions for a given market. // It returns a slice of MarketPosition as defined in the dbpm package. -func CalculateMarketPositions_WPAM_DBPM(db *gorm.DB, marketIdStr string) ([]dbpm.MarketPosition, error) { +func CalculateMarketPositions_WPAM_DBPM(mcl setup.MarketCreationLoader, db *gorm.DB, marketIdStr string) ([]dbpm.MarketPosition, error) { // marketIDUint for needed areas marketIDUint64, err := strconv.ParseUint(marketIdStr, 10, 64) @@ -44,11 +44,10 @@ func CalculateMarketPositions_WPAM_DBPM(db *gorm.DB, marketIdStr string) ([]dbpm } // Fetch bets for the market - var allBetsOnMarket []models.Bet - allBetsOnMarket = tradingdata.GetBetsForMarket(db, marketIDUint) + allBetsOnMarket := tradingdata.GetBetsForMarket(db, marketIDUint) // Get a timeline of probability changes for the market - allProbabilityChangesOnMarket := wpam.CalculateMarketProbabilitiesWPAM(publicResponseMarket.CreatedAt, allBetsOnMarket) + allProbabilityChangesOnMarket := wpam.CalculateMarketProbabilitiesWPAM(mcl, publicResponseMarket.CreatedAt, allBetsOnMarket) // Calculate the distribution of YES and NO shares based on DBPM S_YES, S_NO := dbpm.DivideUpMarketPoolSharesDBPM(allBetsOnMarket, allProbabilityChangesOnMarket) @@ -75,8 +74,8 @@ func CalculateMarketPositions_WPAM_DBPM(db *gorm.DB, marketIdStr string) ([]dbpm } // CalculateMarketPositionForUser_WPAM_DBPM fetches and summarizes the position for a given user in a specific market. -func CalculateMarketPositionForUser_WPAM_DBPM(db *gorm.DB, marketIdStr string, username string) (UserMarketPosition, error) { - marketPositions, err := CalculateMarketPositions_WPAM_DBPM(db, marketIdStr) +func CalculateMarketPositionForUser_WPAM_DBPM(mcl setup.MarketCreationLoader, db *gorm.DB, marketIdStr string, username string) (UserMarketPosition, error) { + marketPositions, err := CalculateMarketPositions_WPAM_DBPM(mcl, db, marketIdStr) if err != nil { return UserMarketPosition{}, err } @@ -95,8 +94,8 @@ func CalculateMarketPositionForUser_WPAM_DBPM(db *gorm.DB, marketIdStr string, u // CheckOppositeSharesOwned determines the number of opposite shares a user holds and needs to sell, // as well as the type of those shares (YES or NO). -func CheckOppositeSharesOwned(db *gorm.DB, marketIDStr string, username string, betRequestOutcome string) (int64, string, error) { - userMarketPositions, err := CalculateMarketPositionForUser_WPAM_DBPM(db, marketIDStr, username) +func CheckOppositeSharesOwned(mcl setup.MarketCreationLoader, db *gorm.DB, marketIDStr string, username string, betRequestOutcome string) (int64, string, error) { + userMarketPositions, err := CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketIDStr, username) if err != nil { return 0, "", err // Return the error if fetching the market positions fails. } diff --git a/backend/handlers/positions/positionsmath_test.go b/backend/handlers/positions/positionsmath_test.go new file mode 100644 index 00000000..c6bba4c5 --- /dev/null +++ b/backend/handlers/positions/positionsmath_test.go @@ -0,0 +1,29 @@ +package positions + +import ( + "socialpredict/models/modelstesting" + "socialpredict/setup" + "socialpredict/setup/setuptesting" + "testing" + + "gorm.io/gorm" +) + +func TestCalculateMarketPositions_WPAM_DBPM(t *testing.T) { + tests := []struct { + Name string + MCL setup.MarketCreationLoader + DB *gorm.DB + }{ + { + Name: "", + MCL: setuptesting.BuildInitialMarketAppConfig(t, .5, 0, 0, 0), + DB: modelstesting.NewFakeDB(t), + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + t.Skip() + }) + } +} From 4385b67d08ce2a069828edb5976fc114f5d43cab Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:06:06 -0400 Subject: [PATCH 16/26] Use market creation loader in listbetshandler --- backend/handlers/bets/listbetshandler.go | 75 ++++++++++++------------ 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/backend/handlers/bets/listbetshandler.go b/backend/handlers/bets/listbetshandler.go index f3320f01..1e164532 100644 --- a/backend/handlers/bets/listbetshandler.go +++ b/backend/handlers/bets/listbetshandler.go @@ -7,6 +7,7 @@ import ( "socialpredict/handlers/math/probabilities/wpam" "socialpredict/handlers/tradingdata" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "sort" "strconv" @@ -24,51 +25,53 @@ type BetDisplayInfo struct { PlacedAt time.Time `json:"placedAt"` } -func MarketBetsDisplayHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - marketIdStr := vars["marketId"] +func MarketBetsDisplayHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + marketIdStr := vars["marketId"] - // Convert marketId to uint - parsedUint64, err := strconv.ParseUint(marketIdStr, 10, 32) - if err != nil { - // handle error - } + // Convert marketId to uint + parsedUint64, err := strconv.ParseUint(marketIdStr, 10, 32) + if err != nil { + // handle error + } - // Convert uint64 to uint safely. - marketIDUint := uint(parsedUint64) - - // Database connection - db := util.GetDB() - - // Fetch bets for the market - bets := tradingdata.GetBetsForMarket(db, marketIDUint) - - // feed in the time created - // note we are not using GetPublicResponseMarketByID because of circular import - var market models.Market - result := db.Where("ID = ?", marketIdStr).First(&market) - if result.Error != nil { - // Handle error, for example: - if errors.Is(result.Error, gorm.ErrRecordNotFound) { - // Market not found - } else { - // Other error fetching market + // Convert uint64 to uint safely. + marketIDUint := uint(parsedUint64) + + // Database connection + db := util.GetDB() + + // Fetch bets for the market + bets := tradingdata.GetBetsForMarket(db, marketIDUint) + + // feed in the time created + // note we are not using GetPublicResponseMarketByID because of circular import + var market models.Market + result := db.Where("ID = ?", marketIdStr).First(&market) + if result.Error != nil { + // Handle error, for example: + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + // Market not found + } else { + // Other error fetching market + } + return // Make sure to return or appropriately handle the error } - return // Make sure to return or appropriately handle the error - } - // Process bets and calculate market probability at the time of each bet - betsDisplayInfo := processBetsForDisplay(market.CreatedAt, bets, db) + // Process bets and calculate market probability at the time of each bet + betsDisplayInfo := processBetsForDisplay(mcl, market.CreatedAt, bets, db) - // Respond with the bets display information - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(betsDisplayInfo) + // Respond with the bets display information + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(betsDisplayInfo) + } } -func processBetsForDisplay(marketCreatedAtTime time.Time, bets []models.Bet, db *gorm.DB) []BetDisplayInfo { +func processBetsForDisplay(mcl setup.MarketCreationLoader, marketCreatedAtTime time.Time, bets []models.Bet, db *gorm.DB) []BetDisplayInfo { // Calculate probabilities using the fetched bets - probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(marketCreatedAtTime, bets) + probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(mcl, marketCreatedAtTime, bets) var betsDisplayInfo []BetDisplayInfo From 73951af25bae126624ff7e35841e000e1deb600a Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:06:33 -0400 Subject: [PATCH 17/26] Use market creation loader in sellpositionhandler --- backend/handlers/bets/sellpositionhandler.go | 133 ++++++++++--------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/backend/handlers/bets/sellpositionhandler.go b/backend/handlers/bets/sellpositionhandler.go index d4c8ba45..8ce04105 100644 --- a/backend/handlers/bets/sellpositionhandler.go +++ b/backend/handlers/bets/sellpositionhandler.go @@ -7,87 +7,90 @@ import ( "socialpredict/handlers/positions" "socialpredict/middleware" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "strconv" "time" ) -func SellPositionHandler(w http.ResponseWriter, r *http.Request) { - // Only allow POST requests - if r.Method != http.MethodPost { - http.Error(w, "Method not supported", http.StatusMethodNotAllowed) - return - } +func SellPositionHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + // Only allow POST requests + if r.Method != http.MethodPost { + http.Error(w, "Method not supported", http.StatusMethodNotAllowed) + return + } - db := util.GetDB() // Get the database connection - user, httperr := middleware.ValidateUserAndEnforcePasswordChangeGetUser(r, db) - if httperr != nil { - http.Error(w, httperr.Error(), httperr.StatusCode) - return - } + db := util.GetDB() // Get the database connection + user, httperr := middleware.ValidateUserAndEnforcePasswordChangeGetUser(r, db) + if httperr != nil { + http.Error(w, httperr.Error(), httperr.StatusCode) + return + } - var redeemRequest models.Bet - err := json.NewDecoder(r.Body).Decode(&redeemRequest) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } + var redeemRequest models.Bet + err := json.NewDecoder(r.Body).Decode(&redeemRequest) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - // get the marketID in string format - marketIDStr := strconv.FormatUint(uint64(redeemRequest.MarketID), 10) + // get the marketID in string format + marketIDStr := strconv.FormatUint(uint64(redeemRequest.MarketID), 10) - // Validate the request similar to PlaceBetHandler - betutils.CheckMarketStatus(db, redeemRequest.MarketID) + // Validate the request similar to PlaceBetHandler + betutils.CheckMarketStatus(db, redeemRequest.MarketID) - // Calculate the net aggregate positions for the user - userNetPosition, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(db, marketIDStr, user.Username) - if userNetPosition.NoSharesOwned == 0 && userNetPosition.YesSharesOwned == 0 { - http.Error(w, "No position found for the given market", http.StatusBadRequest) - return - } + // Calculate the net aggregate positions for the user + userNetPosition, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketIDStr, user.Username) + if userNetPosition.NoSharesOwned == 0 && userNetPosition.YesSharesOwned == 0 { + http.Error(w, "No position found for the given market", http.StatusBadRequest) + return + } - // Check if the user is trying to redeem more than they own - if (redeemRequest.Outcome == "YES" && redeemRequest.Amount > userNetPosition.YesSharesOwned) || - (redeemRequest.Outcome == "NO" && redeemRequest.Amount > userNetPosition.NoSharesOwned) { - http.Error(w, "Redeem amount exceeds available position", http.StatusBadRequest) - return - } + // Check if the user is trying to redeem more than they own + if (redeemRequest.Outcome == "YES" && redeemRequest.Amount > userNetPosition.YesSharesOwned) || + (redeemRequest.Outcome == "NO" && redeemRequest.Amount > userNetPosition.NoSharesOwned) { + http.Error(w, "Redeem amount exceeds available position", http.StatusBadRequest) + return + } - // Proceed with redemption logic - // For simplicity, we're just creating a negative bet to represent the sale - redeemRequest.Amount = -redeemRequest.Amount // Negate the amount to indicate sale + // Proceed with redemption logic + // For simplicity, we're just creating a negative bet to represent the sale + redeemRequest.Amount = -redeemRequest.Amount // Negate the amount to indicate sale - // Create a new Bet object - bet := models.Bet{ - Username: user.Username, - MarketID: redeemRequest.MarketID, - Amount: redeemRequest.Amount, - PlacedAt: time.Now(), // Set the current time as the placement time - Outcome: redeemRequest.Outcome, - } + // Create a new Bet object + bet := models.Bet{ + Username: user.Username, + MarketID: redeemRequest.MarketID, + Amount: redeemRequest.Amount, + PlacedAt: time.Now(), // Set the current time as the placement time + Outcome: redeemRequest.Outcome, + } - // Validate the final bet before putting into database - if err := betutils.ValidateSale(db, &bet); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } + // Validate the final bet before putting into database + if err := betutils.ValidateSale(db, &bet); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } - // Deduct the bet and switching sides fee amount from the user's balance - user.AccountBalance -= redeemRequest.Amount + // Deduct the bet and switching sides fee amount from the user's balance + user.AccountBalance -= redeemRequest.Amount - // Update the user's balance in the database - if err := db.Save(&user).Error; err != nil { - http.Error(w, "Error updating user balance: "+err.Error(), http.StatusInternalServerError) - return - } + // Update the user's balance in the database + if err := db.Save(&user).Error; err != nil { + http.Error(w, "Error updating user balance: "+err.Error(), http.StatusInternalServerError) + return + } - result := db.Create(&bet) - if result.Error != nil { - http.Error(w, result.Error.Error(), http.StatusInternalServerError) - return - } + result := db.Create(&bet) + if result.Error != nil { + http.Error(w, result.Error.Error(), http.StatusInternalServerError) + return + } - // Return a success response - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(redeemRequest) + // Return a success response + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(redeemRequest) + } } From 68f33483298271d277d68a3e26ee7d6ca6b4f12a Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:07:10 -0400 Subject: [PATCH 18/26] Use market creation loader in marketdetailshandler --- .../handlers/markets/marketdetailshandler.go | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/backend/handlers/markets/marketdetailshandler.go b/backend/handlers/markets/marketdetailshandler.go index f4a33891..93d0efb7 100644 --- a/backend/handlers/markets/marketdetailshandler.go +++ b/backend/handlers/markets/marketdetailshandler.go @@ -9,6 +9,7 @@ import ( "socialpredict/handlers/tradingdata" usersHandlers "socialpredict/handlers/users" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "strconv" @@ -24,61 +25,63 @@ type MarketDetailHandlerResponse struct { TotalVolume int64 `json:"totalVolume"` } -func MarketDetailsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - marketId := vars["marketId"] +func MarketDetailsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + marketId := vars["marketId"] - // Parsing a String to an Unsigned Integer, base10, 64bits - marketIDUint64, err := strconv.ParseUint(marketId, 10, 64) - if err != nil { - http.Error(w, "Invalid market ID", http.StatusBadRequest) - return - } + // Parsing a String to an Unsigned Integer, base10, 64bits + marketIDUint64, err := strconv.ParseUint(marketId, 10, 64) + if err != nil { + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return + } - marketIDUint := uint(marketIDUint64) + marketIDUint := uint(marketIDUint64) - // open up database to utilize connection pooling - db := util.GetDB() + // open up database to utilize connection pooling + db := util.GetDB() - // Fetch all bets for the market - bets := tradingdata.GetBetsForMarket(db, marketIDUint) + // Fetch all bets for the market + bets := tradingdata.GetBetsForMarket(db, marketIDUint) - // return the PublicResponse type with information about the market - publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketId) - if err != nil { - http.Error(w, "Invalid market ID", http.StatusBadRequest) - return - } + // return the PublicResponse type with information about the market + publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketId) + if err != nil { + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return + } - // Calculate probabilities using the fetched bets - probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(publicResponseMarket.CreatedAt, bets) + // Calculate probabilities using the fetched bets + probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(mcl, publicResponseMarket.CreatedAt, bets) - // find the number of users on the market - numUsers := models.GetNumMarketUsers(bets) - if err != nil { - http.Error(w, "Error retrieving number of users.", http.StatusInternalServerError) - return - } + // find the number of users on the market + numUsers := models.GetNumMarketUsers(bets) + if err != nil { + http.Error(w, "Error retrieving number of users.", http.StatusInternalServerError) + return + } - // market volume is equivalent to the sum of all bets - marketVolume := marketmath.GetMarketVolume(bets) - if err != nil { - // Handle error - } + // market volume is equivalent to the sum of all bets + marketVolume := marketmath.GetMarketVolume(bets) + if err != nil { + // Handle error + } - // get market creator - // Fetch the Creator's public information using utility function - publicCreator := usersHandlers.GetPublicUserInfo(db, publicResponseMarket.CreatorUsername) + // get market creator + // Fetch the Creator's public information using utility function + publicCreator := usersHandlers.GetPublicUserInfo(db, publicResponseMarket.CreatorUsername) - // Manually construct the response - response := MarketDetailHandlerResponse{ - Market: publicResponseMarket, - Creator: publicCreator, - ProbabilityChanges: probabilityChanges, - NumUsers: numUsers, - TotalVolume: marketVolume, - } + // Manually construct the response + response := MarketDetailHandlerResponse{ + Market: publicResponseMarket, + Creator: publicCreator, + ProbabilityChanges: probabilityChanges, + NumUsers: numUsers, + TotalVolume: marketVolume, + } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + } } From 1bed242188844572cfe915e78c21a7cf5db1fe4f Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:07:36 -0400 Subject: [PATCH 19/26] Use market creation loader in userpositionmarkethandler --- .../users/userpositiononmarkethandler.go | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/backend/handlers/users/userpositiononmarkethandler.go b/backend/handlers/users/userpositiononmarkethandler.go index c322ce8f..f38ebf56 100644 --- a/backend/handlers/users/userpositiononmarkethandler.go +++ b/backend/handlers/users/userpositiononmarkethandler.go @@ -5,29 +5,32 @@ import ( "net/http" "socialpredict/handlers/positions" "socialpredict/middleware" + "socialpredict/setup" "socialpredict/util" "github.com/gorilla/mux" ) -func UserMarketPositionHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - marketId := vars["marketId"] +func UserMarketPositionHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + marketId := vars["marketId"] - // Open up database to utilize connection pooling - db := util.GetDB() - user, httperr := middleware.ValidateTokenAndGetUser(r, db) - if httperr != nil { - http.Error(w, "Invalid token: "+httperr.Error(), http.StatusUnauthorized) - return - } + // Open up database to utilize connection pooling + db := util.GetDB() + user, httperr := middleware.ValidateTokenAndGetUser(r, db) + if httperr != nil { + http.Error(w, "Invalid token: "+httperr.Error(), http.StatusUnauthorized) + return + } - userPosition, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(db, marketId, user.Username) - if err != nil { - http.Error(w, "Error calculating user market position: "+err.Error(), http.StatusInternalServerError) - return - } + userPosition, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketId, user.Username) + if err != nil { + http.Error(w, "Error calculating user market position: "+err.Error(), http.StatusInternalServerError) + return + } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(userPosition) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(userPosition) + } } From cde9a0cbea18834d89bf944c85646aa6f170c26f Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:08:07 -0400 Subject: [PATCH 20/26] Use market creation loader in positionshandler --- .../handlers/positions/positionshandler.go | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/backend/handlers/positions/positionshandler.go b/backend/handlers/positions/positionshandler.go index 157d8ee1..c6fb8ef6 100644 --- a/backend/handlers/positions/positionshandler.go +++ b/backend/handlers/positions/positionshandler.go @@ -4,42 +4,47 @@ import ( "encoding/json" "net/http" "socialpredict/errors" + "socialpredict/setup" "socialpredict/util" "github.com/gorilla/mux" ) -func MarketDBPMPositionsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - marketIdStr := vars["marketId"] +func MarketDBPMPositionsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + marketIdStr := vars["marketId"] - // open up database to utilize connection pooling - db := util.GetDB() + // open up database to utilize connection pooling + db := util.GetDB() - marketDBPMPositions, err := CalculateMarketPositions_WPAM_DBPM(db, marketIdStr) - if errors.HandleHTTPError(w, err, http.StatusBadRequest, "Invalid request or data processing error.") { - return // Stop execution if there was an error. - } + marketDBPMPositions, err := CalculateMarketPositions_WPAM_DBPM(mcl, db, marketIdStr) + if errors.HandleHTTPError(w, err, http.StatusBadRequest, "Invalid request or data processing error.") { + return // Stop execution if there was an error. + } - // Respond with the bets display information - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(marketDBPMPositions) + // Respond with the bets display information + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(marketDBPMPositions) + } } -func MarketDBPMUserPositionsHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - marketIdStr := vars["marketId"] - userNameStr := vars["username"] +func MarketDBPMUserPositionsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + marketIdStr := vars["marketId"] + userNameStr := vars["username"] - // open up database to utilize connection pooling - db := util.GetDB() + // open up database to utilize connection pooling + db := util.GetDB() - marketDBPMPositions, err := CalculateMarketPositionForUser_WPAM_DBPM(db, marketIdStr, userNameStr) - if errors.HandleHTTPError(w, err, http.StatusBadRequest, "Invalid request or data processing error.") { - return // Stop execution if there was an error. - } + marketDBPMPositions, err := CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketIdStr, userNameStr) + if errors.HandleHTTPError(w, err, http.StatusBadRequest, "Invalid request or data processing error.") { + return // Stop execution if there was an error. + } - // Respond with the bets display information - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(marketDBPMPositions) + // Respond with the bets display information + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(marketDBPMPositions) + } } From cdde9ecde440b3285cdfcf62beb75245b6bd18f4 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:08:35 -0400 Subject: [PATCH 21/26] Use market creation loader in marketprojectedprobability --- .../markets/marketprojectedprobability.go | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/backend/handlers/markets/marketprojectedprobability.go b/backend/handlers/markets/marketprojectedprobability.go index 230a6d47..05b38a4f 100644 --- a/backend/handlers/markets/marketprojectedprobability.go +++ b/backend/handlers/markets/marketprojectedprobability.go @@ -7,6 +7,7 @@ import ( "socialpredict/handlers/math/probabilities/wpam" "socialpredict/handlers/tradingdata" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "strconv" "time" @@ -15,57 +16,58 @@ import ( ) // ProjectNewProbabilityHandler handles the projection of a new probability based on a new bet. -func ProjectNewProbabilityHandler(w http.ResponseWriter, r *http.Request) { +func ProjectNewProbabilityHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + // Parse market ID, amount, and outcome from the URL + vars := mux.Vars(r) + marketId := vars["marketId"] + amountStr := vars["amount"] + outcome := vars["outcome"] - // Parse market ID, amount, and outcome from the URL - vars := mux.Vars(r) - marketId := vars["marketId"] - amountStr := vars["amount"] - outcome := vars["outcome"] + // Parse marketId string directly into a uint + marketIDUint64, err := strconv.ParseUint(marketId, 10, strconv.IntSize) + if err != nil { + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return + } - // Parse marketId string directly into a uint - marketIDUint64, err := strconv.ParseUint(marketId, 10, strconv.IntSize) - if err != nil { - http.Error(w, "Invalid market ID", http.StatusBadRequest) - return - } - - // Convert to uint (will be either uint32 or uint64 depending on platform) - marketIDUint := uint(marketIDUint64) + // Convert to uint (will be either uint32 or uint64 depending on platform) + marketIDUint := uint(marketIDUint64) - // Convert amount to int64 - amount, err := strconv.ParseInt(amountStr, 10, 64) - if err != nil { - http.Error(w, "Invalid amount value", http.StatusBadRequest) - return - } + // Convert amount to int64 + amount, err := strconv.ParseInt(amountStr, 10, 64) + if err != nil { + http.Error(w, "Invalid amount value", http.StatusBadRequest) + return + } - // Create a new Bet object without a username - newBet := models.Bet{ - Amount: amount, - Outcome: outcome, - PlacedAt: time.Now(), // Assuming the bet is placed now - MarketID: marketIDUint, - } + // Create a new Bet object without a username + newBet := models.Bet{ + Amount: amount, + Outcome: outcome, + PlacedAt: time.Now(), // Assuming the bet is placed now + MarketID: marketIDUint, + } - // Open up database to utilize connection pooling - db := util.GetDB() + // Open up database to utilize connection pooling + db := util.GetDB() - // Fetch all bets for the market - currentBets := tradingdata.GetBetsForMarket(db, marketIDUint) + // Fetch all bets for the market + currentBets := tradingdata.GetBetsForMarket(db, marketIDUint) - // Fetch the market creation time using utility function - publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketId) - if err != nil { - http.Error(w, "Invalid market ID", http.StatusBadRequest) - return - } - marketCreatedAt := publicResponseMarket.CreatedAt + // Fetch the market creation time using utility function + publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketId) + if err != nil { + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return + } + marketCreatedAt := publicResponseMarket.CreatedAt - // Project the new probability - projectedProbability := wpam.ProjectNewProbabilityWPAM(marketCreatedAt, currentBets, newBet) + // Project the new probability + projectedProbability := wpam.ProjectNewProbabilityWPAM(mcl, marketCreatedAt, currentBets, newBet) - // Set the content type to JSON and encode the response - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(projectedProbability) + // Set the content type to JSON and encode the response + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(projectedProbability) + } } From 94f8d71e64c683ada2ef6680a002be34c75664a5 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:08:51 -0400 Subject: [PATCH 22/26] Use market creation loader in listmarkets --- backend/handlers/markets/listmarkets.go | 85 +++++++++++++------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/backend/handlers/markets/listmarkets.go b/backend/handlers/markets/listmarkets.go index bcfc1e6d..08638690 100644 --- a/backend/handlers/markets/listmarkets.go +++ b/backend/handlers/markets/listmarkets.go @@ -10,6 +10,7 @@ import ( "socialpredict/handlers/tradingdata" usersHandlers "socialpredict/handlers/users" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "strconv" @@ -30,55 +31,57 @@ type MarketOverview struct { } // ListMarketsHandler handles the HTTP request for listing markets. -func ListMarketsHandler(w http.ResponseWriter, r *http.Request) { - log.Println("ListMarketsHandler: Request received") - if r.Method != http.MethodGet { - http.Error(w, "Method is not supported.", http.StatusNotFound) - return - } - - db := util.GetDB() - markets, err := ListMarkets(db) - if err != nil { - http.Error(w, "Error fetching markets", http.StatusInternalServerError) - return - } - - var marketOverviews []MarketOverview - for _, market := range markets { - bets := tradingdata.GetBetsForMarket(db, uint(market.ID)) - probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(market.CreatedAt, bets) - numUsers := models.GetNumMarketUsers(bets) - marketVolume := marketmath.GetMarketVolume(bets) - lastProbability := probabilityChanges[len(probabilityChanges)-1].Probability - - creatorInfo := usersHandlers.GetPublicUserInfo(db, market.CreatorUsername) +func ListMarketsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + log.Println("ListMarketsHandler: Request received") + if r.Method != http.MethodGet { + http.Error(w, "Method is not supported.", http.StatusNotFound) + return + } - // return the PublicResponse type with information about the market - marketIDStr := strconv.FormatUint(uint64(market.ID), 10) - publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketIDStr) + db := util.GetDB() + markets, err := ListMarkets(db) if err != nil { - http.Error(w, "Invalid market ID", http.StatusBadRequest) + http.Error(w, "Error fetching markets", http.StatusInternalServerError) return } - marketOverview := MarketOverview{ - Market: publicResponseMarket, - Creator: creatorInfo, - LastProbability: lastProbability, - NumUsers: numUsers, - TotalVolume: marketVolume, + var marketOverviews []MarketOverview + for _, market := range markets { + bets := tradingdata.GetBetsForMarket(db, uint(market.ID)) + probabilityChanges := wpam.CalculateMarketProbabilitiesWPAM(mcl, market.CreatedAt, bets) + numUsers := models.GetNumMarketUsers(bets) + marketVolume := marketmath.GetMarketVolume(bets) + lastProbability := probabilityChanges[len(probabilityChanges)-1].Probability + + creatorInfo := usersHandlers.GetPublicUserInfo(db, market.CreatorUsername) + + // return the PublicResponse type with information about the market + marketIDStr := strconv.FormatUint(uint64(market.ID), 10) + publicResponseMarket, err := marketpublicresponse.GetPublicResponseMarketByID(db, marketIDStr) + if err != nil { + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return + } + + marketOverview := MarketOverview{ + Market: publicResponseMarket, + Creator: creatorInfo, + LastProbability: lastProbability, + NumUsers: numUsers, + TotalVolume: marketVolume, + } + marketOverviews = append(marketOverviews, marketOverview) } - marketOverviews = append(marketOverviews, marketOverview) - } - response := ListMarketsResponse{ - Markets: marketOverviews, - } + response := ListMarketsResponse{ + Markets: marketOverviews, + } - w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(response); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } } } From 11d4ba46aceaafd698361c4403d6d933d47f5569 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:09:09 -0400 Subject: [PATCH 23/26] Use market creation loader in publicuserportfolio --- backend/handlers/users/publicuserportfolio.go | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/backend/handlers/users/publicuserportfolio.go b/backend/handlers/users/publicuserportfolio.go index dd8055ff..7c36cf9d 100644 --- a/backend/handlers/users/publicuserportfolio.go +++ b/backend/handlers/users/publicuserportfolio.go @@ -6,6 +6,7 @@ import ( "net/http" "socialpredict/handlers/positions" "socialpredict/models" + "socialpredict/setup" "socialpredict/util" "sort" "strconv" @@ -28,41 +29,43 @@ type PortfolioTotal struct { TotalSharesOwned int64 `json:"totalSharesOwned"` } -func GetPublicUserPortfolio(w http.ResponseWriter, r *http.Request) { - // Extract the username from the URL - vars := mux.Vars(r) - username := vars["username"] +func GetPublicUserPortfolio(mcl setup.MarketCreationLoader) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + // Extract the username from the URL + vars := mux.Vars(r) + username := vars["username"] - db := util.GetDB() + db := util.GetDB() - // fetch all bets made by a specific user - userbets, err := fetchUserBets(db, username) - if err != nil { - log.Printf("Error fetching user bets: %v", err) - http.Error(w, "Error fetching user bets", http.StatusInternalServerError) - return - } + // fetch all bets made by a specific user + userbets, err := fetchUserBets(db, username) + if err != nil { + log.Printf("Error fetching user bets: %v", err) + http.Error(w, "Error fetching user bets", http.StatusInternalServerError) + return + } - // Create a market map from the user's bets - marketMap := makeUserMarketMap(userbets) + // Create a market map from the user's bets + marketMap := makeUserMarketMap(userbets) - // Process the market map to calculate positions and fetch market titles - userPositionsPortfolio, err := processMarketMap(db, marketMap, username) - if err != nil { - log.Printf("Error processing market map: %v", err) - http.Error(w, "Error processing market map", http.StatusInternalServerError) - return - } + // Process the market map to calculate positions and fetch market titles + userPositionsPortfolio, err := processMarketMap(mcl, db, marketMap, username) + if err != nil { + log.Printf("Error processing market map: %v", err) + http.Error(w, "Error processing market map", http.StatusInternalServerError) + return + } - totalSharesOwned := calculateTotalShares(userPositionsPortfolio) + totalSharesOwned := calculateTotalShares(userPositionsPortfolio) - portfolioTotal := PortfolioTotal{ - PortfolioItems: userPositionsPortfolio, - TotalSharesOwned: totalSharesOwned, - } + portfolioTotal := PortfolioTotal{ + PortfolioItems: userPositionsPortfolio, + TotalSharesOwned: totalSharesOwned, + } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(portfolioTotal) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(portfolioTotal) + } } // fetchUserBets retrieves all bets made by a specific user @@ -103,10 +106,10 @@ func makeUserMarketMap(userbets []models.Bet) map[uint]PortfolioItem { return marketMap } -func processMarketMap(db *gorm.DB, marketMap map[uint]PortfolioItem, username string) ([]PortfolioItem, error) { +func processMarketMap(mcl setup.MarketCreationLoader, db *gorm.DB, marketMap map[uint]PortfolioItem, username string) ([]PortfolioItem, error) { // Calculate market positions for each market for marketID := range marketMap { - position, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(db, strconv.Itoa(int(marketID)), username) + position, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, strconv.Itoa(int(marketID)), username) if err != nil { return nil, err } From d22478883f8d217b213d0e1b201d94da5992fcc9 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:09:38 -0400 Subject: [PATCH 24/26] Use market creation loader in server handlerfuncs --- backend/server/server.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/server/server.go b/backend/server/server.go index 922e37c4..5147d1eb 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -41,21 +41,21 @@ func Start() { router.HandleFunc("/v0/setup", setuphandlers.GetSetupHandler(setup.LoadEconomicsConfig)).Methods("GET") router.HandleFunc("/v0/stats", statshandlers.StatsHandler()).Methods("GET") // markets display, market information - router.HandleFunc("/v0/markets", marketshandlers.ListMarketsHandler).Methods("GET") - router.HandleFunc("/v0/markets/{marketId}", marketshandlers.MarketDetailsHandler).Methods("GET") - router.HandleFunc("/v0/marketprojection/{marketId}/{amount}/{outcome}/", marketshandlers.ProjectNewProbabilityHandler).Methods("GET") + router.HandleFunc("/v0/markets", marketshandlers.ListMarketsHandler(setup.EconomicsConfig())).Methods("GET") + router.HandleFunc("/v0/markets/{marketId}", marketshandlers.MarketDetailsHandler(setup.EconomicsConfig())).Methods("GET") + router.HandleFunc("/v0/marketprojection/{marketId}/{amount}/{outcome}/", marketshandlers.ProjectNewProbabilityHandler(setup.EconomicsConfig())).Methods("GET") // handle market positions, get trades - router.HandleFunc("/v0/markets/bets/{marketId}", betshandlers.MarketBetsDisplayHandler).Methods("GET") - router.HandleFunc("/v0/markets/positions/{marketId}", positions.MarketDBPMPositionsHandler).Methods("GET") - router.HandleFunc("/v0/markets/positions/{marketId}/{username}", positions.MarketDBPMUserPositionsHandler).Methods("GET") + router.HandleFunc("/v0/markets/bets/{marketId}", betshandlers.MarketBetsDisplayHandler(setup.EconomicsConfig())).Methods("GET") + router.HandleFunc("/v0/markets/positions/{marketId}", positions.MarketDBPMPositionsHandler(setup.EconomicsConfig())).Methods("GET") + router.HandleFunc("/v0/markets/positions/{marketId}/{username}", positions.MarketDBPMUserPositionsHandler(setup.EconomicsConfig())).Methods("GET") // show comments on markets // handle public user stuff router.HandleFunc("/v0/userinfo/{username}", usershandlers.GetPublicUserResponse).Methods("GET") router.HandleFunc("/v0/usercredit/{username}", usershandlers.GetUserCreditHandler).Methods("GET") // user portfolio, (which is public) - router.HandleFunc("/v0/portfolio/{username}", usershandlers.GetPublicUserPortfolio).Methods("GET") + router.HandleFunc("/v0/portfolio/{username}", usershandlers.GetPublicUserPortfolio(setup.EconomicsConfig())).Methods("GET") // handle private user stuff, display sensitive profile information to customize router.HandleFunc("/v0/privateprofile", usershandlers.GetPrivateProfileUserResponse) @@ -69,8 +69,8 @@ func Start() { // handle private user actions such as resolve a market, make a bet, create a market, change profile router.HandleFunc("/v0/resolve/{marketId}", marketshandlers.ResolveMarketHandler).Methods("POST") router.HandleFunc("/v0/bet", betshandlers.PlaceBetHandler).Methods("POST") - router.HandleFunc("/v0/userposition/{marketId}", usershandlers.UserMarketPositionHandler) - router.HandleFunc("/v0/sell", betshandlers.SellPositionHandler).Methods("POST") + router.HandleFunc("/v0/userposition/{marketId}", usershandlers.UserMarketPositionHandler(setup.EconomicsConfig())) + router.HandleFunc("/v0/sell", betshandlers.SellPositionHandler(setup.EconomicsConfig())).Methods("POST") router.HandleFunc("/v0/create", marketshandlers.CreateMarketHandler(setup.EconomicsConfig)).Methods("POST") // admin stuff From e441fc2fabda0e940321b8b2c078e42dbda53a04 Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:31:29 -0400 Subject: [PATCH 25/26] Fix codeql warning and remove impossible condition --- backend/handlers/markets/marketdetailshandler.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/backend/handlers/markets/marketdetailshandler.go b/backend/handlers/markets/marketdetailshandler.go index 93d0efb7..4e792c53 100644 --- a/backend/handlers/markets/marketdetailshandler.go +++ b/backend/handlers/markets/marketdetailshandler.go @@ -30,8 +30,8 @@ func MarketDetailsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWrit vars := mux.Vars(r) marketId := vars["marketId"] - // Parsing a String to an Unsigned Integer, base10, 64bits - marketIDUint64, err := strconv.ParseUint(marketId, 10, 64) + // Parsing a String to an Unsigned Integer, base10, 32bits + marketIDUint64, err := strconv.ParseUint(marketId, 10, 32) if err != nil { http.Error(w, "Invalid market ID", http.StatusBadRequest) return @@ -57,10 +57,6 @@ func MarketDetailsHandler(mcl setup.MarketCreationLoader) func(http.ResponseWrit // find the number of users on the market numUsers := models.GetNumMarketUsers(bets) - if err != nil { - http.Error(w, "Error retrieving number of users.", http.StatusInternalServerError) - return - } // market volume is equivalent to the sum of all bets marketVolume := marketmath.GetMarketVolume(bets) From c7c9f2798ce87d55d1ba7ff511a805b954a94cbd Mon Sep 17 00:00:00 2001 From: alacey <25300182+ajlacey@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:36:29 -0400 Subject: [PATCH 26/26] Adjust error handling --- backend/handlers/bets/listbetshandler.go | 3 ++- backend/handlers/bets/sellpositionhandler.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/handlers/bets/listbetshandler.go b/backend/handlers/bets/listbetshandler.go index 1e164532..be5a5a28 100644 --- a/backend/handlers/bets/listbetshandler.go +++ b/backend/handlers/bets/listbetshandler.go @@ -33,7 +33,8 @@ func MarketBetsDisplayHandler(mcl setup.MarketCreationLoader) func(http.Response // Convert marketId to uint parsedUint64, err := strconv.ParseUint(marketIdStr, 10, 32) if err != nil { - // handle error + http.Error(w, "Invalid market ID", http.StatusBadRequest) + return } // Convert uint64 to uint safely. diff --git a/backend/handlers/bets/sellpositionhandler.go b/backend/handlers/bets/sellpositionhandler.go index 8ce04105..ec63d09e 100644 --- a/backend/handlers/bets/sellpositionhandler.go +++ b/backend/handlers/bets/sellpositionhandler.go @@ -42,7 +42,7 @@ func SellPositionHandler(mcl setup.MarketCreationLoader) func(http.ResponseWrite betutils.CheckMarketStatus(db, redeemRequest.MarketID) // Calculate the net aggregate positions for the user - userNetPosition, err := positions.CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketIDStr, user.Username) + userNetPosition, _ := positions.CalculateMarketPositionForUser_WPAM_DBPM(mcl, db, marketIDStr, user.Username) if userNetPosition.NoSharesOwned == 0 && userNetPosition.YesSharesOwned == 0 { http.Error(w, "No position found for the given market", http.StatusBadRequest) return