diff --git a/.gitignore b/.gitignore index 2b70277..38a452d 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,4 @@ fabric.properties .ionide # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,goland,go +/recover.bolt diff --git a/cmd/codeword/main.go b/cmd/codeword/main.go index 3d84e25..a03d31a 100644 --- a/cmd/codeword/main.go +++ b/cmd/codeword/main.go @@ -9,8 +9,17 @@ import ( "os" "os/signal" "syscall" + "time" ) +var ( + commit string = os.Getenv("COMMIT") + buildTime string = os.Getenv("BUILD_TIME") + version string = os.Getenv("VERSION") +) + +// $env:COMMIT=$(git rev-parse --short HEAD); $env:BUILD_TIME=$(Get-Date -UFormat "%Y-%m-%dT%H:%M:%SZ"); $env:VERSION=$(git describe --tags); go run cmd/codeword/main.go + func main() { logger, err := zap.NewProduction() if err != nil { @@ -18,6 +27,12 @@ func main() { os.Exit(1) } + ptime, err := time.Parse(time.RFC3339, buildTime) + if err != nil { + logger.Error("Error parsing build time:", zap.Error(err)) + ptime = time.Now() + } + config, err := initialize.LoadConfig() if err != nil { logger.Fatal("Failed to load config", zap.Error(err)) @@ -26,7 +41,11 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() - if err = app.Run(ctx, *config, logger); err != nil { + if err = app.Run(ctx, *config, logger, app.Build{ + Commit: commit, + Version: version, + BuildTime: ptime.Unix(), + }); err != nil { logger.Fatal("App exited with error", zap.Error(err)) } } diff --git a/deployments/staging/docker-compose.yaml b/deployments/staging/docker-compose.yaml index 534d8f8..e61c3fd 100644 --- a/deployments/staging/docker-compose.yaml +++ b/deployments/staging/docker-compose.yaml @@ -39,6 +39,8 @@ services: KAFKA_TOPIC_TARIFF: "tariffs" DISCOUNT_ADDRESS: "10.8.0.6:9001" GRPC_HOST: "0.0.0.0" + TRASH_LOG_HOST: "10.8.0.15:7113" + MODULE_LOGGER: "codeword-staging" ports: - 10.8.0.6:59664:3000 - 10.8.0.6:59665:9000 diff --git a/go.mod b/go.mod index 427424c..0cb8f2c 100644 --- a/go.mod +++ b/go.mod @@ -14,16 +14,18 @@ require ( github.com/stretchr/testify v1.8.4 github.com/twmb/franz-go v1.15.4 go.mongodb.org/mongo-driver v1.13.1 - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac google.golang.org/grpc v1.60.1 google.golang.org/protobuf v1.32.0 - penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d + penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c ) require ( + github.com/ClickHouse/clickhouse-go v1.5.4 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -35,8 +37,11 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/pierrec/lz4/v4 v4.1.19 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/skeris/appInit v1.0.2 // indirect + github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf // indirect github.com/twmb/franz-go/pkg/kmsg v1.7.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.50.0 // indirect @@ -45,6 +50,7 @@ require ( github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.etcd.io/bbolt v1.3.6 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect @@ -54,5 +60,7 @@ require ( google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/tucnak/telebot.v2 v2.5.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + penahub.gitlab.yandexcloud.net/external/trashlog.git v0.1.2-0.20240523172059-9bbe8a9faa31 // indirect ) diff --git a/go.sum b/go.sum index bac60dd..0cc38fa 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0= +github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0= github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 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= @@ -25,6 +30,7 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= @@ -47,10 +53,12 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -65,6 +73,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -72,6 +81,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -81,28 +91,37 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4= github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pioz/faker v1.7.3 h1:Tez8Emuq0UN+/d6mo3a9m/9ZZ/zdfJk0c5RtRatrceM= github.com/pioz/faker v1.7.3/go.mod h1:xSpay5w/oz1a6+ww0M3vfpe40pSIykeUPeWEc3TvVlc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/skeris/appInit v1.0.2 h1:Hr4KbXYd6kolTVq4cXGqDpgnpmaauiOiKizA1+Ep4KQ= +github.com/skeris/appInit v1.0.2/go.mod h1:4ElEeXWVGzU3dlYq/eMWJ/U5hd+LKisc1z3+ySh1XmY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo= +github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf/go.mod h1:1FsorU3vnXO9xS9SrhUp8fRb/6H/Zfll0rPt1i4GWaA= github.com/twmb/franz-go v1.15.4 h1:qBCkHaiutetnrXjAUWA99D9FEcZVMt2AYwkH3vWEQTw= github.com/twmb/franz-go v1.15.4/go.mod h1:rC18hqNmfo8TMc1kz7CQmHL74PLNF8KVvhflxiiJZCU= github.com/twmb/franz-go/pkg/kmsg v1.7.0 h1:a457IbvezYfA5UkiBvyV3zj0Is3y1i8EJgqjJYoij2E= @@ -124,19 +143,27 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -148,6 +175,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -177,6 +205,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -203,6 +232,9 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -238,8 +270,11 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/tucnak/telebot.v2 v2.5.0 h1:i+NynLo443Vp+Zn3Gv9JBjh3Z/PaiKAQwcnhNI7y6Po= +gopkg.in/tucnak/telebot.v2 v2.5.0/go.mod h1:BgaIIx50PSRS9pG59JH+geT82cfvoJU/IaI5TJdN3v8= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -250,5 +285,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d h1:gbaDt35HMDqOK84WYmDIlXMI7rstUcRqNttaT6Kx1do= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607142502-8257e6c4aa5a h1:dGW8ErUVdwGJBq6uc5AHYn6Yt10CDNkMIpV+yrDDTLs= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607142502-8257e6c4aa5a/go.mod h1:+bPxq2wfW5S1gd+83vZYmHm33AE7nEBfznWS8AM1TKE= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c h1:CWb4UcuNXhd1KTNOmy2U0TJO4+Qxgxrj5cwkyFqbgrk= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c/go.mod h1:+bPxq2wfW5S1gd+83vZYmHm33AE7nEBfznWS8AM1TKE= +penahub.gitlab.yandexcloud.net/external/trashlog.git v0.1.2-0.20240523172059-9bbe8a9faa31 h1:WlRVJnzU0sti+qBq/JTCgFPU0RoxIqGHu7hzDirxE2k= +penahub.gitlab.yandexcloud.net/external/trashlog.git v0.1.2-0.20240523172059-9bbe8a9faa31/go.mod h1:3ml0dAGT8U8RhpevKBfRgG6yKZum8EI2uJxAb2WCIy4= diff --git a/internal/app/app.go b/internal/app/app.go index 3bc7917..1095cea 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,22 +5,33 @@ import ( "codeword/internal/controller/recovery" "codeword/internal/controller/rpc_controllers" "codeword/internal/initialize" + "codeword/internal/models" "codeword/internal/repository" "codeword/internal/server/grpc" httpserver "codeword/internal/server/http" "codeword/internal/services" + "codeword/internal/utils/middleware" "codeword/internal/worker/purge_worker" "codeword/internal/worker/recovery_worker" "codeword/pkg/closer" - "codeword/utils" "context" "errors" + "github.com/themakers/hlog" "github.com/twmb/franz-go/pkg/kgo" "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "penahub.gitlab.yandexcloud.net/external/trashlog.git/app" + "penahub.gitlab.yandexcloud.net/external/trashlog.git/wrappers/zaptrashlog" "time" ) -func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { +type Build struct { + Commit string + Version string + BuildTime int64 +} + +func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger, build Build) error { defer func() { if r := recover(); r != nil { logger.Error("Recovered from a panic", zap.Any("error", r)) @@ -32,6 +43,18 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { ctx, cancel := context.WithCancel(ctx) defer cancel() + clickHouseLogger, err := zaptrashlog.NewCore(ctx, zap.InfoLevel, cfg.TrashLogHost, build.Version, build.Commit, build.BuildTime) + if err != nil { + panic(err) + } + loggerForHlog := logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { + return zapcore.NewTee(core, clickHouseLogger) + })) + + loggerHlog := hlog.New(loggerForHlog).Module(cfg.ModuleLogger) + loggerHlog.With(models.AllFields{}) + loggerHlog.Emit(app.InfoSvcStarted{}) + shutdownGroup := closer.NewCloserGroup() mdb, err := initialize.MongoDB(ctx, cfg) @@ -103,11 +126,15 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { DiscountClient: discountRpcClient, }) - jwtUtil := utils.NewJWT(&cfg) - authMiddleware := utils.NewAuthenticator(jwtUtil) + jwtUtil := middleware.NewJWT(&cfg) - recoveryController := recovery.NewRecoveryController(logger, recoveryService, cfg.DefaultRedirectionURL) - promoCodeController := promocode.NewPromoCodeController(promocode.Deps{Logger: logger, PromoCodeService: promoService, AuthMiddleware: authMiddleware}) + recoveryController := recovery.NewRecoveryController(recovery.Deps{ + Logger: logger, + Service: recoveryService, + DefaultURL: cfg.DefaultRedirectionURL, + RecoveryURL: cfg.RecoveryUrl, + }) + promoCodeController := promocode.NewPromoCodeController(promocode.Deps{Logger: logger, PromoCodeService: promoService}) controllerRpc := rpc_controllers.InitRpcControllers(promoService) grpcServer, err := grpc.NewGRPC(logger) @@ -135,6 +162,8 @@ func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { server := httpserver.NewServer(httpserver.ServerConfig{ Logger: logger, Controllers: []httpserver.Controller{recoveryController, promoCodeController}, + Hlogger: loggerHlog, + JWT: jwtUtil, }) go func() { diff --git a/internal/controller/promocode/promocode_controller.go b/internal/controller/promocode/promocode_controller.go index fae5bdc..cdf7a1d 100644 --- a/internal/controller/promocode/promocode_controller.go +++ b/internal/controller/promocode/promocode_controller.go @@ -4,33 +4,34 @@ import ( "codeword/internal/models" "codeword/internal/repository" "codeword/internal/services" + "codeword/internal/utils/middleware" "errors" "fmt" "github.com/gofiber/fiber/v2" "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw" ) type Deps struct { Logger *zap.Logger PromoCodeService *services.PromoCodeService - AuthMiddleware func(*fiber.Ctx) error } type PromoCodeController struct { logger *zap.Logger promoCodeService *services.PromoCodeService - authMiddleware func(*fiber.Ctx) error } func NewPromoCodeController(deps Deps) *PromoCodeController { return &PromoCodeController{ logger: deps.Logger, promoCodeService: deps.PromoCodeService, - authMiddleware: deps.AuthMiddleware, } } func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error { + userID := middleware.ExtractUserID(c) + hlogger := log_mw.ExtractLogger(c) var req models.PromoCode if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"}) @@ -53,10 +54,48 @@ func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } + var keyType string + var ctxFactor float64 + var keyTargetType string + var ctxTarget string + var ctxAmount int64 + + if createdPromoCode.Bonus.Privilege.PrivilegeID != "" && createdPromoCode.Bonus.Discount.Factor != 0 && createdPromoCode.Bonus.Discount.Factor != 1 { + keyType = "privilege,discount" + keyTargetType = "privilege,service" + ctxTarget = fmt.Sprintf("%s,%s", createdPromoCode.Bonus.Privilege.PrivilegeID, createdPromoCode.Bonus.Discount.Target) + ctxAmount = int64(createdPromoCode.Bonus.Privilege.Amount) + ctxFactor = createdPromoCode.Bonus.Discount.Factor + } else if createdPromoCode.Bonus.Privilege.PrivilegeID != "" { + keyType = "privilege" + keyTargetType = "privilege" + ctxTarget = createdPromoCode.Bonus.Privilege.PrivilegeID + ctxAmount = int64(createdPromoCode.Bonus.Privilege.Amount) + } else if createdPromoCode.Bonus.Discount.Factor != 0 && createdPromoCode.Bonus.Discount.Factor != 1 { + keyType = "discount" + keyTargetType = "service" + ctxFactor = createdPromoCode.Bonus.Discount.Factor + ctxTarget = createdPromoCode.Bonus.Discount.Target + } + + hlogger.Emit(models.InfoPromocodeCreated{ + CtxID: createdPromoCode.ID.String(), + CtxUserID: userID, + KeyType: keyType, + CtxFactor: ctxFactor, + KeyTargetType: keyTargetType, + CtxTarget: ctxTarget, + CtxAmount: ctxAmount, + CtxCode: createdPromoCode.Codeword, + }) + return c.Status(fiber.StatusOK).JSON(createdPromoCode) } func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error { + userID := middleware.ExtractUserID(c) + hlogger := log_mw.ExtractLogger(c) + var req models.ReqEditPromoCode if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"}) @@ -79,6 +118,41 @@ func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } + var keyType string + var ctxFactor float64 + var keyTargetType string + var ctxTarget string + var ctxAmount int64 + + if editedPromoCode.Bonus.Privilege.PrivilegeID != "" && editedPromoCode.Bonus.Discount.Factor != 0 && editedPromoCode.Bonus.Discount.Factor != 1 { + keyType = "privilege,discount" + keyTargetType = "privilege,service" + ctxTarget = fmt.Sprintf("%s,%s", editedPromoCode.Bonus.Privilege.PrivilegeID, editedPromoCode.Bonus.Discount.Target) + ctxAmount = int64(editedPromoCode.Bonus.Privilege.Amount) + ctxFactor = editedPromoCode.Bonus.Discount.Factor + } else if editedPromoCode.Bonus.Privilege.PrivilegeID != "" { + keyType = "privilege" + keyTargetType = "privilege" + ctxTarget = editedPromoCode.Bonus.Privilege.PrivilegeID + ctxAmount = int64(editedPromoCode.Bonus.Privilege.Amount) + } else if editedPromoCode.Bonus.Discount.Factor != 0 && editedPromoCode.Bonus.Discount.Factor != 1 { + keyType = "discount" + keyTargetType = "service" + ctxFactor = editedPromoCode.Bonus.Discount.Factor + ctxTarget = editedPromoCode.Bonus.Discount.Target + } + + hlogger.Emit(models.InfoPromocodeUpdated{ + CtxID: editedPromoCode.ID.String(), + CtxUserID: userID, + KeyType: keyType, + CtxFactor: ctxFactor, + KeyTargetType: keyTargetType, + CtxTarget: ctxTarget, + CtxAmount: ctxAmount, + CtxCode: editedPromoCode.Codeword, + }) + return c.Status(fiber.StatusOK).JSON(editedPromoCode) } @@ -101,13 +175,8 @@ func (p *PromoCodeController) GetList(c *fiber.Ctx) error { } func (p *PromoCodeController) Activate(c *fiber.Ctx) error { - err := p.authMiddleware(c) - fmt.Println("SKER0", err) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err}) - } - - userID := c.Locals(models.AuthJWTDecodedUserIDKey).(string) + userID := middleware.ExtractUserID(c) + hlogger := log_mw.ExtractLogger(c) fmt.Println("SKER1", userID) if userID == "" { return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "failed to get jwt payload"}) @@ -123,7 +192,7 @@ func (p *PromoCodeController) Activate(c *fiber.Ctx) error { } fmt.Println("SKER2", req) - greetings, err := p.promoCodeService.ActivatePromo(c.Context(), &req, userID) + promocode, err := p.promoCodeService.ActivatePromo(c.Context(), &req, userID) fmt.Println("SKER3", err) if err != nil { p.logger.Error("Failed to activate promocode", zap.Error(err)) @@ -134,20 +203,43 @@ func (p *PromoCodeController) Activate(c *fiber.Ctx) error { case errors.Is(err, repository.ErrPromoCodeAlreadyActivated): return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "PromoCode already activated"}) case errors.Is(err, repository.ErrPromoCodeExpired): + hlogger.Emit(models.InfoPromocodeDeadlined{ + + CtxID: promocode.ID.String(), + }) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) case errors.Is(err, repository.ErrPromoCodeExhausted): + hlogger.Emit(models.InfoPromocodeExhausted{ + CtxID: promocode.ID.String(), + }) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode exhausted"}) default: return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } } - return c.Status(fiber.StatusOK).JSON(models.ActivateResp{Greetings: greetings}) + if req.Codeword != "" { + hlogger.Emit(models.InfoPromocodeActivated{ + CtxID: promocode.ID.String(), + CtxUserID: userID, + CtxCode: req.Codeword, + }) + } else if req.FastLink != "" { + hlogger.Emit(models.InfoFastlinkActivated{ + CtxID: promocode.ID.String(), + CtxUserID: userID, + CtxPromocodeID: req.FastLink, + }) + } + + return c.Status(fiber.StatusOK).JSON(models.ActivateResp{Greetings: promocode.Greetings}) } func (p *PromoCodeController) Delete(c *fiber.Ctx) error { - promoCodeID := c.Params("promocodeID") + userID := middleware.ExtractUserID(c) + hlogger := log_mw.ExtractLogger(c) + promoCodeID := c.Params("promocodeID") if promoCodeID == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode ID is required"}) } @@ -163,10 +255,18 @@ func (p *PromoCodeController) Delete(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } + hlogger.Emit(models.InfoPromocodeDeleted{ + CtxID: promoCodeID, + CtxUserID: userID, + }) + return c.SendStatus(fiber.StatusOK) } func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error { + userID := middleware.ExtractUserID(c) + hlogger := log_mw.ExtractLogger(c) + var req struct { PromoCodeID string `json:"id"` } @@ -189,6 +289,12 @@ func (p *PromoCodeController) CreateFastLink(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } + hlogger.Emit(models.InfoFastlinkCreated{ + CtxID: fastLink, + CtxPromocodeID: req.PromoCodeID, + CtxUserID: userID, + }) + return c.Status(fiber.StatusCreated).JSON(fiber.Map{"fastlink": fastLink}) } diff --git a/internal/controller/recovery/recovery_controller.go b/internal/controller/recovery/recovery_controller.go index 3f0f8cd..543e0ce 100644 --- a/internal/controller/recovery/recovery_controller.go +++ b/internal/controller/recovery/recovery_controller.go @@ -9,20 +9,30 @@ import ( "fmt" "github.com/gofiber/fiber/v2" "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw" "time" ) -type RecoveryController struct { - logger *zap.Logger - service *services.RecoveryService - defaultURL string +type Deps struct { + Logger *zap.Logger + Service *services.RecoveryService + DefaultURL string + RecoveryURL string } -func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService, defaultRedirectionURL string) *RecoveryController { +type RecoveryController struct { + logger *zap.Logger + service *services.RecoveryService + defaultURL string + recoveryURL string +} + +func NewRecoveryController(deps Deps) *RecoveryController { return &RecoveryController{ - logger: logger, - service: service, - defaultURL: defaultRedirectionURL, + logger: deps.Logger, + service: deps.Service, + defaultURL: deps.DefaultURL, + recoveryURL: deps.RecoveryURL, } } @@ -45,6 +55,7 @@ func (r *RecoveryController) HandlePingDB(c *fiber.Ctx) error { } func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { + hlogger := log_mw.ExtractLogger(c) var req models.RecoveryRequest if err := c.BodyParser(&req); err != nil { r.logger.Error("Failed to parse recovery request", zap.Error(err)) @@ -79,11 +90,11 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { sign := base64.URLEncoding.EncodeToString(key) id, err := r.service.StoreRecoveryRecord(c.Context(), models.StoreRecDeps{ - UserID: user.ID.Hex(), - Email: user.Email, - Key: sign, - Url: signUrl, - }) + UserID: user.ID.Hex(), + Email: user.Email, + Key: sign, + Url: signUrl, + }) if err != nil { r.logger.Error("Failed to store recovery record", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) @@ -102,36 +113,44 @@ func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } + hlogger.Emit(models.InfoPasswordRestorationRequested{ + CtxID: id, + CtxUserID: user.ID.Hex(), + CtxReturnURL: r.recoveryURL + signWithID, + CtxEmail: req.Email, + }) + return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Recovery email sent successfully"}) } func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { + hlogger := log_mw.ExtractLogger(c) sign := c.Params("sign") record, err := r.service.GetRecoveryRecord(c.Context(), sign) if err != nil { r.logger.Error("Recovery link expired", zap.String("signature", sign)) - return c.Redirect("https://shub.pena.digital/recover/expired") + return c.Redirect("https://shub.pena.digital/recover/expired") } if time.Since(record.CreatedAt) > 15*time.Minute { r.logger.Error("Recovery link expired", zap.String("signature", sign)) - return c.Redirect(record.SignUrl+"/expired") - } + return c.Redirect(record.SignUrl + "/expired") + } tokens, err := r.service.ExchangeForTokens(record.UserID, record.Sign) if err != nil { r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err)) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } - c.Cookie(&fiber.Cookie{ - Name: "refreshToken", - Value: tokens["refreshToken"], - Domain: ".pena.digital", - Expires: time.Now().Add(30 * 24 * time.Hour), - Secure: true, - HTTPOnly: true, - }) + c.Cookie(&fiber.Cookie{ + Name: "refreshToken", + Value: tokens["refreshToken"], + Domain: ".pena.digital", + Expires: time.Now().Add(30 * 24 * time.Hour), + Secure: true, + HTTPOnly: true, + }) c.Cookie(&fiber.Cookie{ Name: "refreshToken", @@ -142,5 +161,10 @@ func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error { HTTPOnly: true, }) + hlogger.Emit(models.InfoPasswordRestored{ + CtxID: record.ID.String(), + CtxUserID: record.UserID, + }) + return c.Redirect(record.SignUrl + "?auth=" + tokens["accessToken"]) } diff --git a/internal/initialize/config.go b/internal/initialize/config.go index f540f03..d6077e0 100644 --- a/internal/initialize/config.go +++ b/internal/initialize/config.go @@ -41,6 +41,8 @@ type Config struct { Audience string `env:"JWT_AUDIENCE,required"` GrpcHost string `env:"GRPC_HOST" envDefault:"localhost"` GrpcPort string `env:"GRPC_PORT" envDefault:"9000"` + TrashLogHost string `env:"TRASH_LOG_HOST" envDefault:"localhost:7113"` + ModuleLogger string `env:"MODULE_LOGGER" envDefault:"codeword-local"` } func LoadConfig() (*Config, error) { diff --git a/internal/models/hlogger_events.go b/internal/models/hlogger_events.go new file mode 100644 index 0000000..b23a14e --- /dev/null +++ b/internal/models/hlogger_events.go @@ -0,0 +1,75 @@ +package models + +type AllFields struct { + CtxUserIP string + CtxUserPort string + KeyDomain string + KeyPath string + CtxID string + CtxUserID string + KeyType string + CtxFactor float64 + KeyTargetType string + CtxTarget string + CtxAmount int64 + CtxCode string + CtxPromocodeID string + CtxReturnURL string + CtxEmail string +} + +type InfoPromocodeCreated struct { + CtxID string //айдишник созданного промокода + CtxUserID string //айдишник юзера из токена + KeyType string //привилегия или скидка. или и то и другое, смотря что заполнено + CtxFactor float64 //множитель скидки + KeyTargetType string //privilege или service + CtxTarget string // айдишник привилегии или сервиса соответственно + CtxAmount int64 // если промик на привилегию + CtxCode string +} +type InfoFastlinkCreated struct { + CtxID string //айдишник созданного промокода + CtxPromocodeID string //айдишник созданного промокода + CtxUserID string //айдишник юзера из токена +} +type InfoPromocodeDeleted struct { + CtxID string //айдишник созданного промокода + CtxUserID string //айдишник юзера из токена +} +type InfoPromocodeUpdated struct { + CtxID string //айдишник промокода + CtxUserID string //айдишник юзера из токена + KeyType string //привилегия или скидка. или и то и другое, смотря что заполнено + CtxFactor float64 //множитель скидки + KeyTargetType string //privilege или service + CtxTarget string // айдишник привилегии или сервиса соответственно + CtxAmount int64 // если промик на привилегию + CtxCode string +} +type InfoPromocodeActivated struct { + CtxID string //айдишник промокода + CtxUserID string //айдишник юзера из токена + CtxCode string +} +type InfoFastlinkActivated struct { + CtxID string //айдишник промокода + CtxUserID string //айдишник юзера из токена + CtxPromocodeID string //айдишник созданного промокода +} +type InfoPromocodeExhausted struct { + CtxID string //айдишник промокода +} +type InfoPromocodeDeadlined struct { + CtxID string //айдишник промокода +} +type InfoPasswordRestorationRequested struct { + CtxID string //айдишник промокода + CtxUserID string //айдишник юзера из токена + CtxReturnURL string // ссылка на восстановление пароля + CtxEmail string +} +type InfoPasswordRestored struct { + CtxID string //айдишник промокода + CtxUserID string //айдишник юзера из токена +} diff --git a/internal/server/http/http_server.go b/internal/server/http/http_server.go index 4bb0aed..6df5235 100644 --- a/internal/server/http/http_server.go +++ b/internal/server/http/http_server.go @@ -1,15 +1,20 @@ package http import ( + "codeword/internal/utils/middleware" "context" "fmt" "github.com/gofiber/fiber/v2" + "github.com/themakers/hlog" "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw" ) type ServerConfig struct { Logger *zap.Logger Controllers []Controller + Hlogger hlog.Logger + JWT *middleware.JWT } type Server struct { @@ -20,7 +25,8 @@ type Server struct { func NewServer(config ServerConfig) *Server { app := fiber.New() - + app.Use(log_mw.ContextLogger(config.Hlogger)) + app.Use("/promocode", middleware.NewAuthenticator(config.JWT)) s := &Server{ Logger: config.Logger, Controllers: config.Controllers, diff --git a/internal/services/promocode_service.go b/internal/services/promocode_service.go index 0b87884..8d267df 100644 --- a/internal/services/promocode_service.go +++ b/internal/services/promocode_service.go @@ -93,30 +93,30 @@ func (s *PromoCodeService) GetPromoCodesList(ctx context.Context, req *models.Ge // разделяется ли она или они всегда вместе, если разделяются то что-то из этого может быть пустым либо все заполеннное, // соответсвенно надо сделать соответствующие проверки до записи в кафку и до отправки в дискаунт сервис -func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq, userID string) (string, error) { +func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.ActivateReq, userID string) (*models.PromoCode, error) { promoCode, err := s.promoCodeRepo.ActivatePromo(ctx, req) fmt.Println("SKER20", err, promoCode, time.Now().Unix()) if err != nil { s.logger.Error("Failed to activate promocode", zap.Error(err)) - return "", err + return nil, err } //todo такая реализация проверок кажется довольно массивной, думаю как то это стоит сделать параллельно обхаживая все условия if promoCode.DueTo < time.Now().Unix() && promoCode.DueTo > 0 { err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) fmt.Println("SKER21", err) if err != nil { - return "", err + return nil, err } - return "", fmt.Errorf("%w: expired on %s", repository.ErrPromoCodeExpired, time.Unix(promoCode.DueTo, 0).Format(time.RFC3339)) + return nil, fmt.Errorf("%w: expired on %s", repository.ErrPromoCodeExpired, time.Unix(promoCode.DueTo, 0).Format(time.RFC3339)) } if promoCode.DueTo == 0 && promoCode.ActivationCount < 0 && promoCode.ActivationLimit != 0 { err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) fmt.Println("SKER22", err) if err != nil { - return "", err + return nil, err } - return "", repository.ErrPromoCodeExhausted + return nil, repository.ErrPromoCodeExhausted } err = s.statsRepo.UpdateStatistics(ctx, req, promoCode, userID) @@ -125,12 +125,12 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa if errors.Is(err, repository.ErrPromoCodeAlreadyActivated) { err := s.promoCodeRepo.IncreaseActivationCount(ctx, promoCode.ID) if err != nil { - return "", err + return nil, err } - return "", repository.ErrPromoCodeAlreadyActivated + return nil, repository.ErrPromoCodeAlreadyActivated } s.logger.Error("Failed add in stats", zap.Error(err)) - return "", err + return nil, err } var postfix string @@ -158,7 +158,7 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa fmt.Println("SKER24", err) if err := s.kafka.Send(ctx, userID, fakeTariff); err != nil { s.logger.Error("Failed to send fake tariff to Kafka", zap.Error(err)) - return "", err + return nil, err } } @@ -205,11 +205,11 @@ func (s *PromoCodeService) ActivatePromo(ctx context.Context, req *models.Activa _, err = s.discountClient.CreateDiscount(ctx, discountRequest) if err != nil { s.logger.Error("Failed to create discount", zap.Error(err)) - return "", err + return nil, err } } - return promoCode.Greetings, nil + return promoCode, nil } func (s *PromoCodeService) DeletePromoCode(ctx context.Context, promoCodeID string) error { diff --git a/utils/authenticator.go b/internal/utils/middleware/authenticator.go similarity index 85% rename from utils/authenticator.go rename to internal/utils/middleware/authenticator.go index 24af308..1c2c860 100644 --- a/utils/authenticator.go +++ b/internal/utils/middleware/authenticator.go @@ -1,9 +1,9 @@ -package utils +package middleware import ( "codeword/internal/models" - "strings" "fmt" + "strings" "github.com/gofiber/fiber/v2" ) @@ -44,3 +44,8 @@ func authenticate(c *fiber.Ctx, jwtUtil *JWT) error { return nil } + +func ExtractUserID(c *fiber.Ctx) string { + userID := c.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string) + return userID +} diff --git a/utils/jwt.go b/internal/utils/middleware/jwt.go similarity index 99% rename from utils/jwt.go rename to internal/utils/middleware/jwt.go index 4584dee..86b52e7 100644 --- a/utils/jwt.go +++ b/internal/utils/middleware/jwt.go @@ -1,4 +1,4 @@ -package utils +package middleware import ( "codeword/internal/initialize" diff --git a/tests/helpers/jwt.go b/tests/helpers/jwt.go index a0134ab..42becda 100644 --- a/tests/helpers/jwt.go +++ b/tests/helpers/jwt.go @@ -2,11 +2,11 @@ package helpers import ( "codeword/internal/initialize" - "codeword/utils" + "codeword/internal/utils/middleware" "strings" ) -func InitializeJWT() *utils.JWT { +func InitializeJWT() *middleware.JWT { publicKey := strings.Replace(`-----BEGIN PUBLIC KEY----- MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69 80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B @@ -29,7 +29,7 @@ func InitializeJWT() *utils.JWT { 7McQvEk12dU/JNTX8wJAOlAtSNjp9tVwpMpC0w2St1eKc1L2SknjeohA5ldoBz8sGeZsPhTU3eHSD1neAZXLKN5K68z3zFBr20ubY9nyLw== -----END RSA PRIVATE KEY-----`, "\t", "", -1) - return utils.NewJWT(&initialize.Config{ + return middleware.NewJWT(&initialize.Config{ PrivateKey: privateKey, PublicKey: publicKey, Audience: "pena",