From 001c9a81403013b1f626970ba7ad77e4c5964b26 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 31 Oct 2024 22:41:32 +0800 Subject: [PATCH] :recycle: Moved account-based post to publisher-based post --- go.mod | 70 +++---- go.sum | 53 +++++ pkg/internal/database/migrator.go | 3 +- pkg/internal/database/source.go | 16 +- pkg/internal/gap/net.go | 15 -- pkg/internal/gap/server.go | 29 ++- pkg/internal/grpc/server.go | 24 ++- pkg/internal/grpc/services.go | 2 +- .../{server => http}/api/articles_api.go | 79 ++++---- .../{server => http}/api/categories_api.go | 10 +- pkg/internal/{server => http}/api/index.go | 7 +- .../{server => http}/api/posts_api.go | 84 ++++---- pkg/internal/http/api/publishers_api.go | 9 + .../api/recommendation_api.go | 15 +- .../{server => http}/api/replies_api.go | 4 +- .../{server => http}/api/stories_api.go | 78 ++++---- .../{server => http}/api/subscriptions_api.go | 160 ++++----------- pkg/internal/{server => http}/api/tags_api.go | 0 pkg/internal/http/api/users_api.go | 31 +++ .../{server => http}/api/what_new_api.dart.go | 19 +- pkg/internal/{server => http}/exts/utils.go | 0 pkg/internal/{server => http}/server.go | 45 ++--- pkg/internal/models/accounts.go | 14 -- pkg/internal/models/categories.go | 6 +- pkg/internal/models/posts.go | 40 ++-- pkg/internal/models/publishers.go | 31 +++ pkg/internal/models/reactions.go | 4 +- pkg/internal/models/realms.go | 9 - pkg/internal/models/subscriptions.go | 22 +-- pkg/internal/server/api/publishers_api.go | 15 -- pkg/internal/server/api/users_api.go | 61 ------ pkg/internal/services/accounts.go | 107 +++------- pkg/internal/services/categories.go | 6 +- pkg/internal/services/posts.go | 73 +++---- pkg/internal/services/publishers.go | 23 +-- pkg/internal/services/realms.go | 67 ------- pkg/internal/services/subscriptions.go | 187 ++++-------------- pkg/main.go | 45 +++-- settings.toml | 20 +- 39 files changed, 559 insertions(+), 924 deletions(-) delete mode 100644 pkg/internal/gap/net.go rename pkg/internal/{server => http}/api/articles_api.go (74%) rename pkg/internal/{server => http}/api/categories_api.go (85%) rename pkg/internal/{server => http}/api/index.go (87%) rename pkg/internal/{server => http}/api/posts_api.go (83%) create mode 100644 pkg/internal/http/api/publishers_api.go rename pkg/internal/{server => http}/api/recommendation_api.go (85%) rename pkg/internal/{server => http}/api/replies_api.go (97%) rename pkg/internal/{server => http}/api/stories_api.go (77%) rename pkg/internal/{server => http}/api/subscriptions_api.go (60%) rename pkg/internal/{server => http}/api/tags_api.go (100%) create mode 100644 pkg/internal/http/api/users_api.go rename pkg/internal/{server => http}/api/what_new_api.dart.go (66%) rename pkg/internal/{server => http}/exts/utils.go (100%) rename pkg/internal/{server => http}/server.go (61%) delete mode 100644 pkg/internal/models/accounts.go create mode 100644 pkg/internal/models/publishers.go delete mode 100644 pkg/internal/models/realms.go delete mode 100644 pkg/internal/server/api/publishers_api.go delete mode 100644 pkg/internal/server/api/users_api.go delete mode 100644 pkg/internal/services/realms.go diff --git a/go.mod b/go.mod index c6cace1..a301e19 100644 --- a/go.mod +++ b/go.mod @@ -1,35 +1,37 @@ module git.solsynth.dev/hydrogen/interactive -go 1.21.6 +go 1.23.2 require ( git.solsynth.dev/hydrogen/dealer v0.0.0-20241015165700-60e4bbfd9782 - github.com/go-playground/validator/v10 v10.17.0 - github.com/gofiber/fiber/v2 v2.52.4 + github.com/go-playground/validator/v10 v10.22.1 + github.com/gofiber/fiber/v2 v2.52.5 github.com/json-iterator/go v1.1.12 github.com/pemistahl/lingua-go v1.4.0 github.com/robfig/cron/v3 v3.0.1 - github.com/rs/zerolog v1.31.0 - github.com/samber/lo v1.39.0 - github.com/spf13/viper v1.18.2 - google.golang.org/grpc v1.65.0 - gorm.io/datatypes v1.2.0 - gorm.io/driver/postgres v1.5.4 - gorm.io/gorm v1.25.6 + github.com/rs/zerolog v1.33.0 + github.com/samber/lo v1.47.0 + github.com/spf13/viper v1.19.0 + google.golang.org/grpc v1.67.1 + gorm.io/datatypes v1.2.4 + gorm.io/driver/postgres v1.5.9 + gorm.io/gorm v1.25.12 ) require ( - github.com/andybalholm/brotli v1.1.0 // indirect + git.solsynth.dev/hypernet/nexus v0.0.0-20241031133156-6bb8eab3fcd8 // indirect + git.solsynth.dev/hypernet/passport v0.0.0-20241031144010-d1f1183beb36 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/fatih/color v1.17.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-playground/form v3.1.4+incompatible // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/consul/api v1.29.1 // indirect + github.com/hashicorp/consul/api v1.30.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -40,49 +42,49 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/serf v0.10.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect - github.com/jackc/pgx/v5 v5.5.1 // 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/jpillora/backoff v1.0.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mbobakov/grpc-consul-resolver v1.5.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect - github.com/philhofer/fwd v1.1.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tinylib/msgp v1.1.8 // indirect + github.com/tinylib/msgp v1.2.2 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.52.0 // indirect + github.com/valyala/fasthttp v1.56.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect - golang.org/x/net v0.28.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/mysql v1.5.2 // indirect + gorm.io/driver/mysql v1.5.7 // indirect ) diff --git a/go.sum b/go.sum index 11e7278..19c817d 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,24 @@ git.solsynth.dev/hydrogen/dealer v0.0.0-20241014131829-4de0c4c969ad h1:QzK7mg+02 git.solsynth.dev/hydrogen/dealer v0.0.0-20241014131829-4de0c4c969ad/go.mod h1:Q51JPkKnV0UoOT/IRmdBh5CyfSlp7s8BRGzgooYHqkI= git.solsynth.dev/hydrogen/dealer v0.0.0-20241015165700-60e4bbfd9782 h1:HUgt8RmDp5AKLlT/QGk4QXcO23OEMVpRYRjgLfOf45c= git.solsynth.dev/hydrogen/dealer v0.0.0-20241015165700-60e4bbfd9782/go.mod h1:Q51JPkKnV0UoOT/IRmdBh5CyfSlp7s8BRGzgooYHqkI= +git.solsynth.dev/hypernet/nexus v0.0.0-20241027051235-ae3583ead196 h1:vTT1Vhz9OJHUh+D07AUFO3jjm3p8/dRo194REny0Wk4= +git.solsynth.dev/hypernet/nexus v0.0.0-20241027051235-ae3583ead196/go.mod h1:fXQsHXGio+7/0U95IitKF07wS4yTdCMp5ms8wpFBwVI= +git.solsynth.dev/hypernet/nexus v0.0.0-20241030155904-3f6ea11d2297 h1:g9huTJFUKPESCKWkcGpVm2RRInGkcwkbL8yR8SBjTFo= +git.solsynth.dev/hypernet/nexus v0.0.0-20241030155904-3f6ea11d2297/go.mod h1:fXQsHXGio+7/0U95IitKF07wS4yTdCMp5ms8wpFBwVI= +git.solsynth.dev/hypernet/nexus v0.0.0-20241031125727-aa624ee45428 h1:1TnXLOzZZKwdneKHynK1qJ/3UL4r/f5Pp3EM+qdL1n4= +git.solsynth.dev/hypernet/nexus v0.0.0-20241031125727-aa624ee45428/go.mod h1:fXQsHXGio+7/0U95IitKF07wS4yTdCMp5ms8wpFBwVI= +git.solsynth.dev/hypernet/nexus v0.0.0-20241031133156-6bb8eab3fcd8 h1:fo9WuAXcmxdGfYXZKTiAbqGLHAkeL7vf0zpwbjoUNc0= +git.solsynth.dev/hypernet/nexus v0.0.0-20241031133156-6bb8eab3fcd8/go.mod h1:fXQsHXGio+7/0U95IitKF07wS4yTdCMp5ms8wpFBwVI= +git.solsynth.dev/hypernet/passport v0.0.0-20241031123850-8ff2648e4c01 h1:YapQJ2C8DqP3+cogPt3wbMwIASiOhEUt56n0jF9IPG8= +git.solsynth.dev/hypernet/passport v0.0.0-20241031123850-8ff2648e4c01/go.mod h1:UbKNgsV2s9ynBlL/8aElbn89gh09qSgu732ozTUOAg0= +git.solsynth.dev/hypernet/passport v0.0.0-20241031132625-39ac016b46e5 h1:M20dSDvOM62juoGaDtbWecs7M1Qma6Kg5bHFfPoqEBc= +git.solsynth.dev/hypernet/passport v0.0.0-20241031132625-39ac016b46e5/go.mod h1:EjUDX5HdTo3J1GfAN5mfDf0JxRspzASj8uysa4V/ow0= +git.solsynth.dev/hypernet/passport v0.0.0-20241031133521-2b4f71e73283 h1:TVH7ltMPpm3ocl3JQjk8nMHuBb8h9OIuAW+KiBUxdxk= +git.solsynth.dev/hypernet/passport v0.0.0-20241031133521-2b4f71e73283/go.mod h1:EjUDX5HdTo3J1GfAN5mfDf0JxRspzASj8uysa4V/ow0= +git.solsynth.dev/hypernet/passport v0.0.0-20241031140851-c3619f6d25b3 h1:CjRgstnj5laWw9nktI/rMGRosSkCdAPET7LYdaId/wk= +git.solsynth.dev/hypernet/passport v0.0.0-20241031140851-c3619f6d25b3/go.mod h1:EjUDX5HdTo3J1GfAN5mfDf0JxRspzASj8uysa4V/ow0= +git.solsynth.dev/hypernet/passport v0.0.0-20241031144010-d1f1183beb36 h1:rzDuXRTCbWJOgfT7bG0cWFcYqbWKnI1aEfiovpXfsdM= +git.solsynth.dev/hypernet/passport v0.0.0-20241031144010-d1f1183beb36/go.mod h1:EjUDX5HdTo3J1GfAN5mfDf0JxRspzASj8uysa4V/ow0= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -15,6 +33,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= @@ -44,6 +63,7 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -58,13 +78,16 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -85,6 +108,7 @@ 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/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= +github.com/hashicorp/consul/api v1.30.0/go.mod h1:B2uGchvaXVW2JhFoS8nqTxMD5PBykr4ebY4JWHTTeLM= github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= @@ -135,10 +159,13 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.5.1 h1:5I9etrGkLrN+2XPCsi6XLlV5DITbSL/xBZdmAxFcXPI= github.com/jackc/pgx/v5 v5.5.1/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= 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/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= @@ -152,6 +179,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -163,6 +191,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -183,6 +212,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-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -212,10 +242,12 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pemistahl/lingua-go v1.4.0 h1:ifYhthrlW7iO4icdubwlduYnmwU37V1sbNrwhKBR4rM= github.com/pemistahl/lingua-go v1.4.0/go.mod h1:ECuM1Hp/3hvyh7k8aWSqNCPlTxLemFZsRjocUf3KgME= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= +github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -246,13 +278,16 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= @@ -265,10 +300,12 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -289,13 +326,16 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tinylib/msgp v1.2.2/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= +github.com/valyala/fasthttp v1.56.0/go.mod h1:sReBt3XZVnudxuLOx4J/fMrJVorWRiWY2koQKgABiVI= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -305,8 +345,10 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -320,6 +362,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -357,6 +400,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -368,6 +412,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -377,10 +422,13 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A= google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -399,10 +447,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/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco= gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04= +gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI= gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= 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/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= @@ -410,3 +461,5 @@ gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHD gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A= gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/pkg/internal/database/migrator.go b/pkg/internal/database/migrator.go index 9bc97d3..6ffa5d2 100644 --- a/pkg/internal/database/migrator.go +++ b/pkg/internal/database/migrator.go @@ -6,8 +6,7 @@ import ( ) var AutoMaintainRange = []any{ - &models.Account{}, - &models.Realm{}, + &models.Publisher{}, &models.Category{}, &models.Tag{}, &models.Post{}, diff --git a/pkg/internal/database/source.go b/pkg/internal/database/source.go index 7602278..e5da27d 100644 --- a/pkg/internal/database/source.go +++ b/pkg/internal/database/source.go @@ -1,24 +1,26 @@ package database import ( + "fmt" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" "github.com/rs/zerolog/log" "github.com/samber/lo" "github.com/spf13/viper" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" - "gorm.io/gorm/schema" ) var C *gorm.DB -func NewSource() error { - var err error +func NewGorm() error { + dsn, err := cruda.NewCrudaConn(gap.Nx).AllocDatabase("passport") + if err != nil { + return fmt.Errorf("failed to alloc database from nexus: %v", err) + } - dialector := postgres.Open(viper.GetString("database.dsn")) - C, err = gorm.Open(dialector, &gorm.Config{NamingStrategy: schema.NamingStrategy{ - TablePrefix: viper.GetString("database.prefix"), - }, Logger: logger.New(&log.Logger, logger.Config{ + C, err = gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.New(&log.Logger, logger.Config{ Colorful: true, IgnoreRecordNotFoundError: true, LogLevel: lo.Ternary(viper.GetBool("debug.database"), logger.Info, logger.Silent), diff --git a/pkg/internal/gap/net.go b/pkg/internal/gap/net.go deleted file mode 100644 index d618851..0000000 --- a/pkg/internal/gap/net.go +++ /dev/null @@ -1,15 +0,0 @@ -package gap - -import "net" - -func GetOutboundIP() (net.IP, error) { - conn, err := net.Dial("udp", "1.1.1.1:80") - if err != nil { - return nil, err - } else { - defer conn.Close() - } - - localAddr := conn.LocalAddr().(*net.UDPAddr) - return localAddr.IP, nil -} diff --git a/pkg/internal/gap/server.go b/pkg/internal/gap/server.go index 29a9e79..ad33470 100644 --- a/pkg/internal/gap/server.go +++ b/pkg/internal/gap/server.go @@ -2,42 +2,51 @@ package gap import ( "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex" + "git.solsynth.dev/hypernet/pusher/pkg/pushkit/pushcon" + "github.com/samber/lo" "strings" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/dealer/pkg/proto" + "git.solsynth.dev/hypernet/nexus/pkg/proto" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) -var H *hyper.HyperConn +var Nx *nex.Conn +var Px *pushcon.Conn -func RegisterService() error { +func InitializeToNexus() error { grpcBind := strings.SplitN(viper.GetString("grpc_bind"), ":", 2) httpBind := strings.SplitN(viper.GetString("bind"), ":", 2) - outboundIp, _ := GetOutboundIP() + outboundIp, _ := nex.GetOutboundIP() grpcOutbound := fmt.Sprintf("%s:%s", outboundIp, grpcBind[1]) httpOutbound := fmt.Sprintf("%s:%s", outboundIp, httpBind[1]) var err error - H, err = hyper.NewHyperConn(viper.GetString("dealer.addr"), &proto.ServiceInfo{ + Nx, err = nex.NewNexusConn(viper.GetString("nexus_addr"), &proto.ServiceInfo{ Id: viper.GetString("id"), - Type: hyper.ServiceTypeInteractiveProvider, - Label: "Passport", + Type: "co", + Label: "Interactive", GrpcAddr: grpcOutbound, - HttpAddr: &httpOutbound, + HttpAddr: lo.ToPtr("http://" + httpOutbound + "/api"), }) if err == nil { go func() { - err := H.KeepRegisterService() + err := Nx.RunRegistering() if err != nil { log.Error().Err(err).Msg("An error occurred while registering service...") } }() } + Px, err = pushcon.NewConn(Nx) + if err != nil { + return fmt.Errorf("error during initialize pushcon: %v", err) + } + return err + } diff --git a/pkg/internal/grpc/server.go b/pkg/internal/grpc/server.go index 859af03..cc07c89 100644 --- a/pkg/internal/grpc/server.go +++ b/pkg/internal/grpc/server.go @@ -1,7 +1,7 @@ package grpc import ( - "git.solsynth.dev/hydrogen/dealer/pkg/proto" + "git.solsynth.dev/hypernet/nexus/pkg/proto" "github.com/spf13/viper" "google.golang.org/grpc" health "google.golang.org/grpc/health/grpc_health_v1" @@ -10,25 +10,29 @@ import ( ) type Server struct { - proto.UnimplementedServiceDirectoryServer + proto.UnimplementedDirectoryServiceServer + + srv *grpc.Server } -var S *grpc.Server +func NewGrpc() *Server { + server := &Server{ + srv: grpc.NewServer(), + } -func NewGRPC() { - S = grpc.NewServer() + health.RegisterHealthServer(server.srv, server) + proto.RegisterDirectoryServiceServer(server.srv, server) - health.RegisterHealthServer(S, &Server{}) - proto.RegisterServiceDirectoryServer(S, &Server{}) + reflection.Register(server.srv) - reflection.Register(S) + return server } -func ListenGRPC() error { +func (v *Server) Listen() error { listener, err := net.Listen("tcp", viper.GetString("grpc_bind")) if err != nil { return err } - return S.Serve(listener) + return v.srv.Serve(listener) } diff --git a/pkg/internal/grpc/services.go b/pkg/internal/grpc/services.go index 6db80d2..1c28c28 100644 --- a/pkg/internal/grpc/services.go +++ b/pkg/internal/grpc/services.go @@ -23,7 +23,7 @@ func (v *Server) BroadcastDeletion(ctx context.Context, request *proto.DeletionR database.C.Delete(model, "account_id = ?", numericId) } } - database.C.Delete(&models.Account{}, "id = ?", numericId) + database.C.Delete(&models.Publisher{}, "id = ?", numericId) } return &proto.DeletionResponse{}, nil diff --git a/pkg/internal/server/api/articles_api.go b/pkg/internal/http/api/articles_api.go similarity index 74% rename from pkg/internal/server/api/articles_api.go rename to pkg/internal/http/api/articles_api.go index 4e76170..93b656c 100644 --- a/pkg/internal/server/api/articles_api.go +++ b/pkg/internal/http/api/articles_api.go @@ -1,15 +1,17 @@ package api import ( - "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "strconv" "time" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" "github.com/gofiber/fiber/v2" jsoniter "github.com/json-iterator/go" @@ -17,12 +19,13 @@ import ( ) func createArticle(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreatePosts", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreatePosts", true); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var data struct { + Publisher uint `json:"publisher"` Alias *string `json:"alias"` Title string `json:"title" validate:"required,max=1024"` Description *string `json:"description"` @@ -37,13 +40,17 @@ func createArticle(c *fiber.Ctx) error { InvisibleUsers []uint `json:"invisible_users_list"` Visibility *int8 `json:"visibility"` IsDraft bool `json:"is_draft"` - RealmAlias *string `json:"realm"` } if err := exts.BindAndValidate(c, &data); err != nil { return err } + publisher, err := services.GetPublisher(data.Publisher, user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + body := models.PostArticleBody{ Thumbnail: data.Thumbnail, Title: data.Title, @@ -68,7 +75,7 @@ func createArticle(c *fiber.Ctx) error { PublishedUntil: data.PublishedUntil, VisibleUsers: data.VisibleUsers, InvisibleUsers: data.InvisibleUsers, - AuthorID: user.ID, + PublisherID: publisher.ID, } if item.PublishedAt == nil { @@ -81,27 +88,15 @@ func createArticle(c *fiber.Ctx) error { item.Visibility = models.PostVisibilityAll } - if data.RealmAlias != nil { - if realm, err := services.GetRealmWithAlias(*data.RealmAlias); err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } else if _, err = services.GetRealmMember(realm.ID, user.ID); err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to post in the realm, access denied: %v", err)) - } else { - item.RealmID = &realm.ID - item.Realm = &realm - } - } - - item, err := services.NewPost(user, item) + item, err = services.NewPost(publisher, item) if err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.new", strconv.Itoa(int(item.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) } @@ -110,12 +105,13 @@ func createArticle(c *fiber.Ctx) error { func editArticle(c *fiber.Ctx) error { id, _ := c.ParamsInt("postId", 0) - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var data struct { + Publisher uint `json:"publisher"` Alias *string `json:"alias"` Title string `json:"title" validate:"required,max=1024"` Description *string `json:"description"` @@ -130,17 +126,21 @@ func editArticle(c *fiber.Ctx) error { InvisibleUsers []uint `json:"invisible_users_list"` Visibility *int8 `json:"visibility"` IsDraft bool `json:"is_draft"` - RealmAlias *string `json:"realm"` } if err := exts.BindAndValidate(c, &data); err != nil { return err } + publisher, err := services.GetPublisher(data.Publisher, user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + var item models.Post if err := database.C.Where(models.Post{ - BaseModel: hyper.BaseModel{ID: uint(id)}, - AuthorID: user.ID, + BaseModel: cruda.BaseModel{ID: uint(id)}, + PublisherID: publisher.ID, }).First(&item).Error; err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } @@ -180,33 +180,22 @@ func editArticle(c *fiber.Ctx) error { item.PublishedUntil = data.PublishedUntil item.VisibleUsers = data.VisibleUsers item.InvisibleUsers = data.InvisibleUsers - item.Author = user + + // Preload publisher data + item.Publisher = publisher if data.Visibility != nil { item.Visibility = *data.Visibility } - if data.RealmAlias != nil { - if realm, err := services.GetRealmWithAlias(*data.RealmAlias); err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } else if _, err = services.GetRealmMember(realm.ID, user.ID); err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to post in the realm, access denied: %v", err)) - } else { - item.RealmID = &realm.ID - item.Realm = &realm - } - } - - var err error if item, err = services.EditPost(item); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.edit", strconv.Itoa(int(item.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) } diff --git a/pkg/internal/server/api/categories_api.go b/pkg/internal/http/api/categories_api.go similarity index 85% rename from pkg/internal/server/api/categories_api.go rename to pkg/internal/http/api/categories_api.go index ca2a221..5aa1fd5 100644 --- a/pkg/internal/server/api/categories_api.go +++ b/pkg/internal/http/api/categories_api.go @@ -1,9 +1,9 @@ package api import ( - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server/exts" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" "github.com/gofiber/fiber/v2" ) @@ -28,7 +28,7 @@ func listCategories(c *fiber.Ctx) error { } func newCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { return err } @@ -51,7 +51,7 @@ func newCategory(c *fiber.Ctx) error { } func editCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { return err } @@ -80,7 +80,7 @@ func editCategory(c *fiber.Ctx) error { } func deleteCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreatePostCategories", true); err != nil { return err } diff --git a/pkg/internal/server/api/index.go b/pkg/internal/http/api/index.go similarity index 87% rename from pkg/internal/server/api/index.go rename to pkg/internal/http/api/index.go index 88612f9..bbf750e 100644 --- a/pkg/internal/server/api/index.go +++ b/pkg/internal/http/api/index.go @@ -7,9 +7,7 @@ import ( func MapAPIs(app *fiber.App, baseURL string) { api := app.Group(baseURL).Name("API") { - api.Get("/users/me", getUserinfo) - api.Get("/users/:account", getOthersInfo) - api.Get("/users/:account/pin", listOthersPinnedPost) + api.Get("/users/:account/pins", listUserPinnedPost) api.Get("/publishers/:name", getPublisher) @@ -51,15 +49,12 @@ func MapAPIs(app *fiber.App, baseURL string) { subscriptions.Get("/users/:userId", getSubscriptionOnUser) subscriptions.Get("/tags/:tagId", getSubscriptionOnTag) subscriptions.Get("/categories/:categoryId", getSubscriptionOnCategory) - subscriptions.Get("/realms/:realmId", getSubscriptionOnRealm) subscriptions.Post("/users/:userId", subscribeToUser) subscriptions.Post("/tags/:tagId", subscribeToTag) subscriptions.Post("/categories/:categoryId", subscribeToCategory) - subscriptions.Post("/realms/:realmId", subscribeToRealm) subscriptions.Delete("/users/:userId", unsubscribeFromUser) subscriptions.Delete("/tags/:tagId", unsubscribeFromTag) subscriptions.Delete("/categories/:categoryId", unsubscribeFromCategory) - subscriptions.Delete("/realms/:realmId", unsubscribeFromRealm) } api.Get("/categories", listCategories) diff --git a/pkg/internal/server/api/posts_api.go b/pkg/internal/http/api/posts_api.go similarity index 83% rename from pkg/internal/server/api/posts_api.go rename to pkg/internal/http/api/posts_api.go index 2f39d15..d186f84 100644 --- a/pkg/internal/server/api/posts_api.go +++ b/pkg/internal/http/api/posts_api.go @@ -2,6 +2,10 @@ package api import ( "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "gorm.io/gorm" "strconv" "strings" @@ -9,38 +13,28 @@ import ( "git.solsynth.dev/hydrogen/dealer/pkg/hyper" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) func universalPostFilter(c *fiber.Ctx, tx *gorm.DB) (*gorm.DB, error) { - realm := c.Query("realm") - tx = services.FilterPostDraft(tx) - if user, authenticated := c.Locals("user").(models.Account); authenticated { + if user, authenticated := c.Locals("user").(authm.Account); authenticated { tx = services.FilterPostWithUserContext(tx, &user) } else { tx = services.FilterPostWithUserContext(tx, nil) } - if len(realm) > 0 { - if realm, err := services.GetRealmWithAlias(realm); err != nil { - return tx, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("realm was not found: %v", err)) - } else { - tx = services.FilterPostWithRealm(tx, realm.ID) - } - } - if c.QueryBool("noReply", true) { tx = services.FilterPostReply(tx) } if len(c.Query("author")) > 0 { - var author models.Account + var author models.Publisher if err := database.C.Where(&hyper.BaseUser{Name: c.Query("author")}).First(&author).Error; err != nil { return tx, fiber.NewError(fiber.StatusNotFound, err.Error()) } @@ -65,7 +59,7 @@ func getPost(c *fiber.Ctx) error { tx := services.FilterPostDraft(database.C) - if user, authenticated := c.Locals("user").(models.Account); authenticated { + if user, authenticated := c.Locals("user").(authm.Account); authenticated { tx = services.FilterPostWithUserContext(tx, &user) } else { tx = services.FilterPostWithUserContext(tx, nil) @@ -218,10 +212,10 @@ func listDraftPost(c *fiber.Ctx) error { take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) tx := services.FilterPostWithAuthorDraft(database.C, user.ID) @@ -250,16 +244,26 @@ func listDraftPost(c *fiber.Ctx) error { } func deletePost(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) id, _ := c.ParamsInt("postId", 0) + publisherId := c.QueryInt("publisherId", 0) + if publisherId <= 0 { + return fiber.NewError(fiber.StatusBadRequest, "missing publisher id in request") + } + + publisher, err := services.GetPublisher(uint(publisherId), user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + var item models.Post if err := database.C.Where(models.Post{ - BaseModel: hyper.BaseModel{ID: uint(id)}, - AuthorID: user.ID, + BaseModel: cruda.BaseModel{ID: uint(id)}, + PublisherID: publisher.ID, }).First(&item).Error; err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } @@ -267,12 +271,11 @@ func deletePost(c *fiber.Ctx) error { if err := services.DeletePost(item); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.delete", strconv.Itoa(int(item.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) } @@ -280,10 +283,10 @@ func deletePost(c *fiber.Ctx) error { } func reactPost(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreateReactions", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreateReactions", true); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var data struct { Symbol string `json:"symbol"` @@ -304,18 +307,17 @@ func reactPost(c *fiber.Ctx) error { if err := database.C.Where("id = ?", c.Params("postId")).Select("id").First(&res).Error; err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to find post to react: %v", err)) } else { - reaction.PostID = &res.ID + reaction.PostID = res.ID } if positive, reaction, err := services.ReactPost(user, reaction); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.react", strconv.Itoa(int(res.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.Status(lo.Ternary(positive, fiber.StatusCreated, fiber.StatusNoContent)).JSON(reaction) @@ -323,10 +325,10 @@ func reactPost(c *fiber.Ctx) error { } func pinPost(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var res models.Post if err := database.C.Where("id = ? AND author_id = ?", c.Params("postId"), user.ID).First(&res).Error; err != nil { @@ -336,24 +338,20 @@ func pinPost(c *fiber.Ctx) error { if status, err := services.PinPost(res); err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } else if status { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.pin", strconv.Itoa(int(res.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) - return c.SendStatus(fiber.StatusOK) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.unpin", strconv.Itoa(int(res.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) - return c.SendStatus(fiber.StatusNoContent) } } diff --git a/pkg/internal/http/api/publishers_api.go b/pkg/internal/http/api/publishers_api.go new file mode 100644 index 0000000..5f9f041 --- /dev/null +++ b/pkg/internal/http/api/publishers_api.go @@ -0,0 +1,9 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" +) + +func getPublisher(c *fiber.Ctx) error { + panic("TODO") +} diff --git a/pkg/internal/server/api/recommendation_api.go b/pkg/internal/http/api/recommendation_api.go similarity index 85% rename from pkg/internal/server/api/recommendation_api.go rename to pkg/internal/http/api/recommendation_api.go index dfb514c..cf2eb16 100644 --- a/pkg/internal/server/api/recommendation_api.go +++ b/pkg/internal/http/api/recommendation_api.go @@ -3,8 +3,11 @@ package api import ( "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) @@ -51,10 +54,10 @@ func listRecommendationNews(c *fiber.Ctx) error { } func listRecommendationFriends(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) @@ -66,9 +69,9 @@ func listRecommendationFriends(c *fiber.Ctx) error { return err } - friends, _ := services.ListAccountFriends(user) - friendList := lo.Map(friends, func(item models.Account, index int) uint { - return item.ID + friends, _ := authkit.ListRelative(gap.Nx, user.ID, int32(authm.RelationshipFriend), true) + friendList := lo.Map(friends, func(item *proto.UserInfo, index int) uint { + return uint(item.GetId()) }) tx = tx.Where("author_id IN ?", friendList) diff --git a/pkg/internal/server/api/replies_api.go b/pkg/internal/http/api/replies_api.go similarity index 97% rename from pkg/internal/server/api/replies_api.go rename to pkg/internal/http/api/replies_api.go index 70c8f51..84ce335 100644 --- a/pkg/internal/server/api/replies_api.go +++ b/pkg/internal/http/api/replies_api.go @@ -23,7 +23,7 @@ func listPostReplies(c *fiber.Ctx) error { } if len(c.Query("author")) > 0 { - var author models.Account + var author models.Publisher if err := database.C.Where(&hyper.BaseUser{Name: c.Query("author")}).First(&author).Error; err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } @@ -66,7 +66,7 @@ func listPostFeaturedReply(c *fiber.Ctx) error { } if len(c.Query("author")) > 0 { - var author models.Account + var author models.Publisher if err := database.C.Where(&hyper.BaseUser{Name: c.Query("author")}).First(&author).Error; err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } diff --git a/pkg/internal/server/api/stories_api.go b/pkg/internal/http/api/stories_api.go similarity index 77% rename from pkg/internal/server/api/stories_api.go rename to pkg/internal/http/api/stories_api.go index 950adff..37cc0ac 100644 --- a/pkg/internal/server/api/stories_api.go +++ b/pkg/internal/http/api/stories_api.go @@ -2,14 +2,17 @@ package api import ( "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "strconv" "time" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" "github.com/gofiber/fiber/v2" jsoniter "github.com/json-iterator/go" @@ -17,12 +20,13 @@ import ( ) func createStory(c *fiber.Ctx) error { - if err := gap.H.EnsureGrantedPerm(c, "CreatePosts", true); err != nil { + if err := sec.EnsureGrantedPerm(c, "CreatePosts", true); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var data struct { + Publisher uint `json:"publisher"` Alias *string `json:"alias"` Title *string `json:"title"` Content string `json:"content" validate:"required,max=4096"` @@ -37,7 +41,6 @@ func createStory(c *fiber.Ctx) error { InvisibleUsers []uint `json:"invisible_users_list"` Visibility *int8 `json:"visibility"` IsDraft bool `json:"is_draft"` - RealmAlias *string `json:"realm"` ReplyTo *uint `json:"reply_to"` RepostTo *uint `json:"repost_to"` } @@ -46,6 +49,11 @@ func createStory(c *fiber.Ctx) error { return err } + publisher, err := services.GetPublisher(data.Publisher, user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + body := models.PostStoryBody{ Thumbnail: data.Thumbnail, Title: data.Title, @@ -70,7 +78,7 @@ func createStory(c *fiber.Ctx) error { IsDraft: data.IsDraft, VisibleUsers: data.VisibleUsers, InvisibleUsers: data.InvisibleUsers, - AuthorID: user.ID, + PublisherID: publisher.ID, } if item.PublishedAt == nil { @@ -100,27 +108,15 @@ func createStory(c *fiber.Ctx) error { } } - if data.RealmAlias != nil { - if realm, err := services.GetRealmWithAlias(*data.RealmAlias); err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } else if _, err = services.GetRealmMember(realm.ID, user.ID); err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to post in the realm, access denied: %v", err)) - } else { - item.RealmID = &realm.ID - item.Realm = &realm - } - } - - item, err := services.NewPost(user, item) + item, err = services.NewPost(publisher, item) if err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.new", strconv.Itoa(int(item.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) } @@ -129,12 +125,13 @@ func createStory(c *fiber.Ctx) error { func editStory(c *fiber.Ctx) error { id, _ := c.ParamsInt("postId", 0) - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) var data struct { + Publisher uint `json:"publisher"` Alias *string `json:"alias"` Title *string `json:"title"` Content string `json:"content" validate:"required,max=4096"` @@ -149,17 +146,21 @@ func editStory(c *fiber.Ctx) error { InvisibleUsers []uint `json:"invisible_users_list"` Visibility *int8 `json:"visibility"` IsDraft bool `json:"is_draft"` - RealmAlias *string `json:"realm"` } if err := exts.BindAndValidate(c, &data); err != nil { return err } + publisher, err := services.GetPublisher(data.Publisher, user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + var item models.Post if err := database.C.Where(models.Post{ - BaseModel: hyper.BaseModel{ID: uint(id)}, - AuthorID: user.ID, + BaseModel: cruda.BaseModel{ID: uint(id)}, + PublisherID: publisher.ID, }).First(&item).Error; err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) } @@ -199,33 +200,22 @@ func editStory(c *fiber.Ctx) error { item.IsDraft = data.IsDraft item.VisibleUsers = data.VisibleUsers item.InvisibleUsers = data.InvisibleUsers - item.Author = user + + // Preload publisher data + item.Publisher = publisher if data.Visibility != nil { item.Visibility = *data.Visibility } - if data.RealmAlias != nil { - if realm, err := services.GetRealmWithAlias(*data.RealmAlias); err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } else if _, err = services.GetRealmMember(realm.ID, user.ID); err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to post in the realm, access denied: %v", err)) - } else { - item.RealmID = &realm.ID - item.Realm = &realm - } - } - - var err error if item, err = services.EditPost(item); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.edit", strconv.Itoa(int(item.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) } diff --git a/pkg/internal/server/api/subscriptions_api.go b/pkg/internal/http/api/subscriptions_api.go similarity index 60% rename from pkg/internal/server/api/subscriptions_api.go rename to pkg/internal/http/api/subscriptions_api.go index e976416..832fbf5 100644 --- a/pkg/internal/server/api/subscriptions_api.go +++ b/pkg/internal/http/api/subscriptions_api.go @@ -2,19 +2,21 @@ package api import ( "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "strconv" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" "github.com/gofiber/fiber/v2" ) func getSubscriptionOnUser(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) otherUserId, err := c.ParamsInt("userId", 0) otherUser, err := services.GetAccountWithID(uint(otherUserId)) @@ -33,10 +35,10 @@ func getSubscriptionOnUser(c *fiber.Ctx) error { } func getSubscriptionOnTag(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) tagId, err := c.ParamsInt("tagId", 0) tag, err := services.GetTagWithID(uint(tagId)) @@ -55,10 +57,10 @@ func getSubscriptionOnTag(c *fiber.Ctx) error { } func getSubscriptionOnCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) categoryId, err := c.ParamsInt("categoryId", 0) category, err := services.GetCategoryWithID(uint(categoryId)) @@ -76,33 +78,11 @@ func getSubscriptionOnCategory(c *fiber.Ctx) error { return c.JSON(subscription) } -func getSubscriptionOnRealm(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - realmId, err := c.ParamsInt("realmId", 0) - realm, err := services.GetRealmWithID(uint(realmId)) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err)) - } - - subscription, err := services.GetSubscriptionOnRealm(user, realm) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get subscription: %v", err)) - } else if subscription == nil { - return fiber.NewError(fiber.StatusNotFound, "subscription does not exist") - } - - return c.JSON(subscription) -} - func subscribeToUser(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) otherUserId, err := c.ParamsInt("userId", 0) otherUser, err := services.GetAccountWithID(uint(otherUserId)) @@ -115,22 +95,21 @@ func subscribeToUser(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to user: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.subscribe.users", strconv.Itoa(int(otherUser.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.JSON(subscription) } func subscribeToTag(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) tagId, err := c.ParamsInt("tagId", 0) tag, err := services.GetTagWithID(uint(tagId)) @@ -143,22 +122,21 @@ func subscribeToTag(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to tag: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.subscribe.tags", strconv.Itoa(int(tag.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.JSON(subscription) } func subscribeToCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) categoryId, err := c.ParamsInt("categoryId", 0) category, err := services.GetCategoryWithID(uint(categoryId)) @@ -171,50 +149,21 @@ func subscribeToCategory(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to category: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.subscribe.categories", strconv.Itoa(int(category.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), - ) - - return c.JSON(subscription) -} - -func subscribeToRealm(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - realmId, err := c.ParamsInt("realmId", 0) - realm, err := services.GetRealmWithID(uint(realmId)) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err)) - } - - subscription, err := services.SubscribeToRealm(user, realm) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to subscribe to realm: %v", err)) - } - - _ = gap.H.RecordAuditLog( - user.ID, - "posts.subscribe.realms", - strconv.Itoa(int(realm.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.JSON(subscription) } func unsubscribeFromUser(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) otherUserId, err := c.ParamsInt("userId", 0) otherUser, err := services.GetAccountWithID(uint(otherUserId)) @@ -227,22 +176,21 @@ func unsubscribeFromUser(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from user: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.unsubscribe.users", strconv.Itoa(int(otherUser.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.SendStatus(fiber.StatusOK) } func unsubscribeFromTag(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) tagId, err := c.ParamsInt("tagId", 0) tag, err := services.GetTagWithID(uint(tagId)) @@ -255,22 +203,21 @@ func unsubscribeFromTag(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from tag: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.unsubscribe.tags", strconv.Itoa(int(tag.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.SendStatus(fiber.StatusOK) } func unsubscribeFromCategory(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) categoryId, err := c.ParamsInt("categoryId", 0) category, err := services.GetCategoryWithID(uint(categoryId)) @@ -283,40 +230,11 @@ func unsubscribeFromCategory(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from category: %v", err)) } - _ = gap.H.RecordAuditLog( - user.ID, + _ = authkit.AddEventExt( + gap.Nx, "posts.unsubscribe.categories", strconv.Itoa(int(category.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), - ) - - return c.SendStatus(fiber.StatusOK) -} - -func unsubscribeFromRealm(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - realmId, err := c.ParamsInt("realmId", 0) - realm, err := services.GetRealmWithID(uint(realmId)) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get realm: %v", err)) - } - - err = services.UnsubscribeFromRealm(user, realm) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to unsubscribe from realm: %v", err)) - } - - _ = gap.H.RecordAuditLog( - user.ID, - "posts.unsubscribe.realms", - strconv.Itoa(int(realm.ID)), - c.IP(), - c.Get(fiber.HeaderUserAgent), + c, ) return c.SendStatus(fiber.StatusOK) diff --git a/pkg/internal/server/api/tags_api.go b/pkg/internal/http/api/tags_api.go similarity index 100% rename from pkg/internal/server/api/tags_api.go rename to pkg/internal/http/api/tags_api.go diff --git a/pkg/internal/http/api/users_api.go b/pkg/internal/http/api/users_api.go new file mode 100644 index 0000000..ab088bc --- /dev/null +++ b/pkg/internal/http/api/users_api.go @@ -0,0 +1,31 @@ +package api + +import ( + "git.solsynth.dev/hydrogen/dealer/pkg/hyper" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" + "github.com/gofiber/fiber/v2" +) + +func listUserPinnedPost(c *fiber.Ctx) error { + account := c.Params("account") + + var user models.Publisher + if err := database.C. + Where(&hyper.BaseUser{Name: account}). + First(&user).Error; err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + tx := services.FilterPostDraft(database.C) + tx = tx.Where("author_id = ?", user.ID) + tx = tx.Where("pinned_at IS NOT NULL") + + items, err := services.ListPost(tx, 100, 0, "published_at DESC") + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(items) +} diff --git a/pkg/internal/server/api/what_new_api.dart.go b/pkg/internal/http/api/what_new_api.dart.go similarity index 66% rename from pkg/internal/server/api/what_new_api.dart.go rename to pkg/internal/http/api/what_new_api.dart.go index d1c92dc..21af243 100644 --- a/pkg/internal/server/api/what_new_api.dart.go +++ b/pkg/internal/http/api/what_new_api.dart.go @@ -1,40 +1,29 @@ package api import ( - "fmt" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "github.com/gofiber/fiber/v2" ) func getWhatsNew(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { + if err := sec.EnsureAuthenticated(c); err != nil { return err } - user := c.Locals("user").(models.Account) + user := c.Locals("user").(authm.Account) pivot := c.QueryInt("pivot", 0) if pivot < 0 { return fiber.NewError(fiber.StatusBadRequest, "pivot must be greater than zero") } - realm := c.Query("realm") - tx := services.FilterPostDraft(database.C) tx = services.FilterPostWithUserContext(tx, &user) tx = tx.Where("id > ?", pivot) - if len(realm) > 0 { - if realm, err := services.GetRealmWithAlias(realm); err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("realm was not found: %v", err)) - } else { - tx = services.FilterPostWithRealm(tx, realm.ID) - } - } - countTx := tx count, err := services.CountPost(countTx) if err != nil { diff --git a/pkg/internal/server/exts/utils.go b/pkg/internal/http/exts/utils.go similarity index 100% rename from pkg/internal/server/exts/utils.go rename to pkg/internal/http/exts/utils.go diff --git a/pkg/internal/server/server.go b/pkg/internal/http/server.go similarity index 61% rename from pkg/internal/server/server.go rename to pkg/internal/http/server.go index 6145620..42c553c 100644 --- a/pkg/internal/server/server.go +++ b/pkg/internal/http/server.go @@ -1,13 +1,11 @@ -package server +package http import ( + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "git.solsynth.dev/hypernet/passport/pkg/authkit" "strings" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server/api" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http/api" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/idempotency" @@ -17,10 +15,14 @@ import ( "github.com/spf13/viper" ) -var app *fiber.App +var IReader *sec.InternalTokenReader -func NewServer() { - app = fiber.New(fiber.Config{ +type App struct { + app *fiber.App +} + +func NewServer() *App { + app := fiber.New(fiber.Config{ DisableStartupMessage: true, EnableIPValidation: true, ServerHeader: "Hydrogen.Interactive", @@ -54,23 +56,18 @@ func NewServer() { Output: log.Logger, })) - tablePrefix := viper.GetString("database.prefix") - app.Use(gap.H.AuthMiddleware) - app.Use(hyper.LinkAccountMiddleware[models.Account]( - database.C, - tablePrefix+"accounts", - func(u hyper.BaseUser) models.Account { - return models.Account{ - BaseUser: u, - } - }, - )) + app.Use(sec.ContextMiddleware(IReader)) + app.Use(authkit.GetAccountFromUserInfo) api.MapAPIs(app, "/api") -} -func Listen() { - if err := app.Listen(viper.GetString("bind")); err != nil { - log.Fatal().Err(err).Msg("An error occurred when starting server...") + return &App{ + app: app, + } +} + +func (v *App) Listen() { + if err := v.app.Listen(viper.GetString("bind")); err != nil { + log.Fatal().Err(err).Msg("An error occurred when starting http...") } } diff --git a/pkg/internal/models/accounts.go b/pkg/internal/models/accounts.go deleted file mode 100644 index 7ec983c..0000000 --- a/pkg/internal/models/accounts.go +++ /dev/null @@ -1,14 +0,0 @@ -package models - -import "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - -type Account struct { - hyper.BaseUser - - Posts []Post `json:"posts" gorm:"foreignKey:AuthorID"` - Reactions []Reaction `json:"reactions"` - Subscriptions []Subscription `json:"subscriptions" gorm:"foreginKey:FollowerID"` - - TotalUpvote int `json:"total_upvote"` - TotalDownvote int `json:"total_downvote"` -} diff --git a/pkg/internal/models/categories.go b/pkg/internal/models/categories.go index d4dc8fd..46bd45f 100644 --- a/pkg/internal/models/categories.go +++ b/pkg/internal/models/categories.go @@ -1,9 +1,9 @@ package models -import "git.solsynth.dev/hydrogen/dealer/pkg/hyper" +import "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" type Tag struct { - hyper.BaseModel + cruda.BaseModel Alias string `json:"alias" gorm:"uniqueIndex" validate:"lowercase"` Name string `json:"name"` @@ -12,7 +12,7 @@ type Tag struct { } type Category struct { - hyper.BaseModel + cruda.BaseModel Alias string `json:"alias" gorm:"uniqueIndex" validate:"lowercase,alphanum"` Name string `json:"name"` diff --git a/pkg/internal/models/posts.go b/pkg/internal/models/posts.go index 7aca54f..53b2f53 100644 --- a/pkg/internal/models/posts.go +++ b/pkg/internal/models/posts.go @@ -1,9 +1,10 @@ package models import ( + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "time" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" "gorm.io/datatypes" ) @@ -23,23 +24,21 @@ const ( ) type Post struct { - hyper.BaseModel + cruda.BaseModel - Type string `json:"type"` - Body datatypes.JSONMap `json:"body" gorm:"index:,type:gin"` - Language string `json:"language"` - Alias *string `json:"alias"` - AreaAlias *string `json:"area_alias"` - Tags []Tag `json:"tags" gorm:"many2many:post_tags"` - Categories []Category `json:"categories" gorm:"many2many:post_categories"` - Reactions []Reaction `json:"reactions"` - Replies []Post `json:"replies" gorm:"foreignKey:ReplyID"` - ReplyID *uint `json:"reply_id"` - RepostID *uint `json:"repost_id"` - RealmID *uint `json:"realm_id"` - ReplyTo *Post `json:"reply_to" gorm:"foreignKey:ReplyID"` - RepostTo *Post `json:"repost_to" gorm:"foreignKey:RepostID"` - Realm *Realm `json:"realm"` + Type string `json:"type"` + Body datatypes.JSONMap `json:"body" gorm:"index:,type:gin"` + Language string `json:"language"` + Alias *string `json:"alias"` + AliasPrefix *string `json:"alias_prefix"` + Tags []Tag `json:"tags" gorm:"many2many:post_tags"` + Categories []Category `json:"categories" gorm:"many2many:post_categories"` + Reactions []Reaction `json:"reactions"` + Replies []Post `json:"replies" gorm:"foreignKey:ReplyID"` + ReplyID *uint `json:"reply_id"` + RepostID *uint `json:"repost_id"` + ReplyTo *Post `json:"reply_to" gorm:"foreignKey:ReplyID"` + RepostTo *Post `json:"repost_to" gorm:"foreignKey:RepostID"` VisibleUsers datatypes.JSONSlice[uint] `json:"visible_users_list"` InvisibleUsers datatypes.JSONSlice[uint] `json:"invisible_users_list"` @@ -56,8 +55,11 @@ type Post struct { TotalUpvote int `json:"total_upvote"` TotalDownvote int `json:"total_downvote"` - AuthorID uint `json:"author_id"` - Author Account `json:"author"` + RealmID *uint `json:"realm_id"` + Realm *authm.Realm `json:"realm" gorm:"-"` + + PublisherID uint `json:"publisher_id"` + Publisher Publisher `json:"publisher"` Metric PostMetric `json:"metric" gorm:"-"` } diff --git a/pkg/internal/models/publishers.go b/pkg/internal/models/publishers.go new file mode 100644 index 0000000..dca7558 --- /dev/null +++ b/pkg/internal/models/publishers.go @@ -0,0 +1,31 @@ +package models + +import "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + +const ( + PublisherTypePersonal = iota + PublisherTypeOrganization + PublisherTypeAnonymous +) + +type Publisher struct { + cruda.BaseModel + + Type int `json:"type"` + + Name string `json:"name" gorm:"uniqueIndex"` + Nick string `json:"nick"` + Description string `json:"description"` + Avatar string `json:"avatar"` + Banner string `json:"banner"` + + Posts []Post `json:"posts" gorm:"foreignKey:AuthorID"` + Reactions []Reaction `json:"reactions"` + Subscriptions []Subscription `json:"subscriptions" gorm:"foreginKey:FollowerID"` + + TotalUpvote int `json:"total_upvote"` + TotalDownvote int `json:"total_downvote"` + + RealmID *uint `json:"realm_id"` + AccountID *uint `json:"account_id"` +} diff --git a/pkg/internal/models/reactions.go b/pkg/internal/models/reactions.go index da1762a..a392ce2 100644 --- a/pkg/internal/models/reactions.go +++ b/pkg/internal/models/reactions.go @@ -20,6 +20,6 @@ type Reaction struct { Symbol string `json:"symbol"` Attitude ReactionAttitude `json:"attitude"` - PostID *uint `json:"post_id"` - AccountID uint `json:"account_id"` + PostID uint `json:"post_id"` + AccountID uint `json:"account_id"` } diff --git a/pkg/internal/models/realms.go b/pkg/internal/models/realms.go deleted file mode 100644 index ea1e211..0000000 --- a/pkg/internal/models/realms.go +++ /dev/null @@ -1,9 +0,0 @@ -package models - -import "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - -type Realm struct { - hyper.BaseRealm - - Posts []Post `json:"posts"` -} diff --git a/pkg/internal/models/subscriptions.go b/pkg/internal/models/subscriptions.go index 1bda417..f2b1cb6 100644 --- a/pkg/internal/models/subscriptions.go +++ b/pkg/internal/models/subscriptions.go @@ -1,18 +1,16 @@ package models -import "git.solsynth.dev/hydrogen/dealer/pkg/hyper" +import "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" type Subscription struct { - hyper.BaseModel + cruda.BaseModel - FollowerID uint `json:"follower_id"` - Follower Account `json:"follower"` - AccountID *uint `json:"account_id,omitempty"` - Account *Account `json:"account,omitempty"` - TagID *uint `json:"tag_id,omitempty"` - Tag Tag `json:"tag,omitempty"` - CategoryID *uint `json:"category_id,omitempty"` - Category Category `json:"category,omitempty"` - RealmID *uint `json:"realm_id,omitempty"` - Realm Realm `json:"realm,omitempty"` + FollowerID uint `json:"follower_id"` + Follower Publisher `json:"follower"` + AccountID *uint `json:"account_id,omitempty"` + Account *Publisher `json:"account,omitempty"` + TagID *uint `json:"tag_id,omitempty"` + Tag Tag `json:"tag,omitempty"` + CategoryID *uint `json:"category_id,omitempty"` + Category Category `json:"category,omitempty"` } diff --git a/pkg/internal/server/api/publishers_api.go b/pkg/internal/server/api/publishers_api.go deleted file mode 100644 index f0ccf78..0000000 --- a/pkg/internal/server/api/publishers_api.go +++ /dev/null @@ -1,15 +0,0 @@ -package api - -import ( - "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" - "github.com/gofiber/fiber/v2" -) - -func getPublisher(c *fiber.Ctx) error { - alias := c.Params("name") - if out, err := services.GetPublisher(alias); err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } else { - return c.JSON(out) - } -} diff --git a/pkg/internal/server/api/users_api.go b/pkg/internal/server/api/users_api.go deleted file mode 100644 index 85328b6..0000000 --- a/pkg/internal/server/api/users_api.go +++ /dev/null @@ -1,61 +0,0 @@ -package api - -import ( - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" - "github.com/gofiber/fiber/v2" -) - -func getUserinfo(c *fiber.Ctx) error { - if err := gap.H.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - var data models.Account - if err := database.C. - Where(&hyper.BaseModel{ID: user.ID}). - First(&data).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - return c.JSON(data) -} - -func getOthersInfo(c *fiber.Ctx) error { - account := c.Params("account") - - var data models.Account - if err := database.C. - Where(&hyper.BaseUser{Name: account}). - First(&data).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - return c.JSON(data) -} - -func listOthersPinnedPost(c *fiber.Ctx) error { - account := c.Params("account") - - var user models.Account - if err := database.C. - Where(&hyper.BaseUser{Name: account}). - First(&user).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - tx := services.FilterPostDraft(database.C) - tx = tx.Where("author_id = ?", user.ID) - tx = tx.Where("pinned_at IS NOT NULL") - - items, err := services.ListPost(tx, 100, 0, "published_at DESC") - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(items) -} diff --git a/pkg/internal/services/accounts.go b/pkg/internal/services/accounts.go index dea3efd..8c79e5b 100644 --- a/pkg/internal/services/accounts.go +++ b/pkg/internal/services/accounts.go @@ -1,84 +1,24 @@ package services import ( - "context" "fmt" - "time" - - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/dealer/pkg/proto" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + "git.solsynth.dev/hypernet/pusher/pkg/pushkit" "github.com/rs/zerolog/log" - "github.com/samber/lo" ) -func GetAccountWithID(id uint) (models.Account, error) { - var account models.Account +func GetAccountWithID(id uint) (models.Publisher, error) { + var account models.Publisher if err := database.C.Where("id = ?", id).First(&account).Error; err != nil { return account, fmt.Errorf("unable to get account by id: %v", err) } return account, nil } -func ListAccountFriends(user models.Account) ([]models.Account, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return nil, fmt.Errorf("failed to listing account friends: %v", err) - } - result, err := proto.NewAuthClient(pc).ListUserFriends(ctx, &proto.ListUserRelativeRequest{ - UserId: uint64(user.ID), - IsRelated: true, - }) - if err != nil { - return nil, fmt.Errorf("failed to listing account friends: %v", err) - } - - out := lo.Map(result.Data, func(item *proto.SimpleUserInfo, index int) uint { - return uint(item.Id) - }) - - var accounts []models.Account - if err = database.C.Where("id IN ?", out).Find(&accounts).Error; err != nil { - return nil, fmt.Errorf("failed to linking listed account friends: %v", err) - } - - return accounts, nil -} - -func ListAccountBlockedUsers(user models.Account) ([]models.Account, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return nil, fmt.Errorf("failed to listing account blocked users: %v", err) - } - result, err := proto.NewAuthClient(pc).ListUserBlocklist(ctx, &proto.ListUserRelativeRequest{ - UserId: uint64(user.ID), - IsRelated: true, - }) - if err != nil { - return nil, fmt.Errorf("failed to listing account blocked users: %v", err) - } - - out := lo.Map(result.Data, func(item *proto.SimpleUserInfo, index int) uint { - return uint(item.Id) - }) - - var accounts []models.Account - if err = database.C.Where("id IN ?", out).Find(&accounts).Error; err != nil { - return nil, fmt.Errorf("failed to linking listed blocked users: %v", err) - } - - return accounts, nil -} - -func ModifyPosterVoteCount(user models.Account, isUpvote bool, delta int) error { +func ModifyPosterVoteCount(user models.Publisher, isUpvote bool, delta int) error { if isUpvote { user.TotalUpvote += delta } else { @@ -88,32 +28,29 @@ func ModifyPosterVoteCount(user models.Account, isUpvote bool, delta int) error return database.C.Save(&user).Error } -func NotifyPosterAccount(user models.Account, post models.Post, title, body string, subtitle *string) error { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return err +func NotifyPosterAccount(pub models.Publisher, post models.Post, title, body string, subtitle ...string) error { + if pub.AccountID == nil { + return nil } - _, err = proto.NewNotifierClient(pc).NotifyUser(ctx, &proto.NotifyUserRequest{ - UserId: uint64(user.ID), - Notify: &proto.NotifyRequest{ - Topic: "interactive.feedback", - Title: title, - Subtitle: subtitle, - Body: body, - Metadata: hyper.EncodeMap(map[string]any{ - "related_post": TruncatePostContent(post), - }), - IsRealtime: false, - IsForcePush: true, + + if len(subtitle) == 0 { + subtitle = append(subtitle, "") + } + + err := authkit.NotifyUser(gap.Nx, uint64(*pub.AccountID), pushkit.Notification{ + Topic: "interactive.feedback", + Title: title, + Subtitle: subtitle[0], + Body: body, + Priority: 4, + Metadata: map[string]any{ + "related_post": TruncatePostContent(post), }, }) if err != nil { log.Warn().Err(err).Msg("An error occurred when notify account...") } else { - log.Debug().Uint("uid", user.ID).Msg("Notified account.") + log.Debug().Uint("uid", pub.ID).Msg("Notified account.") } return err diff --git a/pkg/internal/services/categories.go b/pkg/internal/services/categories.go index 4d7d29c..ee21547 100644 --- a/pkg/internal/services/categories.go +++ b/pkg/internal/services/categories.go @@ -2,9 +2,9 @@ package services import ( "errors" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" "strings" - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" "gorm.io/gorm" @@ -28,7 +28,7 @@ func GetCategory(alias string) (models.Category, error) { func GetCategoryWithID(id uint) (models.Category, error) { var category models.Category if err := database.C.Where(models.Category{ - BaseModel: hyper.BaseModel{ID: id}, + BaseModel: cruda.BaseModel{ID: id}, }).First(&category).Error; err != nil { return category, err } @@ -64,7 +64,7 @@ func DeleteCategory(category models.Category) error { func GetTagWithID(id uint) (models.Tag, error) { var tag models.Tag if err := database.C.Where(models.Tag{ - BaseModel: hyper.BaseModel{ID: id}, + BaseModel: cruda.BaseModel{ID: id}, }).First(&tag).Error; err != nil { return tag, err } diff --git a/pkg/internal/services/posts.go b/pkg/internal/services/posts.go index 9d7c45d..15bec17 100644 --- a/pkg/internal/services/posts.go +++ b/pkg/internal/services/posts.go @@ -3,6 +3,10 @@ package services import ( "errors" "fmt" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "regexp" "strconv" "time" @@ -11,12 +15,11 @@ import ( "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" "github.com/rs/zerolog/log" "github.com/samber/lo" - "github.com/spf13/viper" "gorm.io/datatypes" "gorm.io/gorm" ) -func FilterPostWithUserContext(tx *gorm.DB, user *models.Account) *gorm.DB { +func FilterPostWithUserContext(tx *gorm.DB, user *authm.Account) *gorm.DB { if user == nil { return tx.Where("visibility = ?", models.PostVisibilityAll) } @@ -28,13 +31,13 @@ func FilterPostWithUserContext(tx *gorm.DB, user *models.Account) *gorm.DB { NoneVisibility = models.PostVisibilityNone ) - friends, _ := ListAccountFriends(*user) - allowlist := lo.Map(friends, func(item models.Account, index int) uint { - return item.ID + friends, _ := authkit.ListRelative(gap.Nx, user.ID, int32(authm.RelationshipFriend), true) + allowlist := lo.Map(friends, func(item *proto.UserInfo, index int) uint { + return uint(item.GetId()) }) - blocked, _ := ListAccountBlockedUsers(*user) - blocklist := lo.Map(blocked, func(item models.Account, index int) uint { - return item.ID + blocked, _ := authkit.ListRelative(gap.Nx, user.ID, int32(authm.RelationshipBlocked), true) + blocklist := lo.Map(blocked, func(item *proto.UserInfo, index int) uint { + return uint(item.GetId()) }) tx = tx.Where( @@ -54,17 +57,15 @@ func FilterPostWithUserContext(tx *gorm.DB, user *models.Account) *gorm.DB { } func FilterPostWithCategory(tx *gorm.DB, alias string) *gorm.DB { - prefix := viper.GetString("database.prefix") - return tx.Joins(fmt.Sprintf("JOIN %spost_categories ON %sposts.id = %spost_categories.post_id", prefix, prefix, prefix)). - Joins(fmt.Sprintf("JOIN %scategories ON %scategories.id = %spost_categories.category_id", prefix, prefix, prefix)). - Where(fmt.Sprintf("%scategories.alias = ?", prefix), alias) + return tx.Joins("JOIN post_categories ON posts.id = post_categories.post_id"). + Joins("JOIN categories ON categories.id = post_categories.category_id"). + Where("categories.alias = ?", alias) } func FilterPostWithTag(tx *gorm.DB, alias string) *gorm.DB { - prefix := viper.GetString("database.prefix") - return tx.Joins(fmt.Sprintf("JOIN %spost_tags ON %sposts.id = %spost_tags.post_id", prefix, prefix, prefix)). - Joins(fmt.Sprintf("JOIN %stags ON %stags.id = %spost_tags.tag_id", prefix, prefix, prefix)). - Where(fmt.Sprintf("%stags.alias = ?", prefix), alias) + return tx.Joins("JOIN post_tags ON posts.id = post_tags.post_id"). + Joins("JOIN tags ON tags.id = post_tags.tag_id"). + Where("tags.alias = ?", alias) } func FilterPostWithRealm(tx *gorm.DB, id uint) *gorm.DB { @@ -289,7 +290,7 @@ func EnsurePostCategoriesAndTags(item models.Post) (models.Post, error) { return item, nil } -func NewPost(user models.Account, item models.Post) (models.Post, error) { +func NewPost(user models.Publisher, item models.Post) (models.Post, error) { if item.Alias != nil && len(*item.Alias) == 0 { item.Alias = nil } @@ -302,9 +303,9 @@ func NewPost(user models.Account, item models.Post) (models.Post, error) { } if item.Realm != nil { - item.AreaAlias = &item.Realm.Alias + item.AliasPrefix = &item.Realm.Alias } else { - item.AreaAlias = &user.Name + item.AliasPrefix = &user.Name } log.Debug().Any("body", item.Body).Msg("Posting a post...") @@ -316,16 +317,6 @@ func NewPost(user models.Account, item models.Post) (models.Post, error) { return item, err } - if item.RealmID != nil { - log.Debug().Uint("id", *item.RealmID).Msg("Looking for post author realm...") - member, err := GetRealmMember(*item.RealmID, user.ID) - if err != nil { - return item, fmt.Errorf("you aren't a part of that realm: %v", err) - } else if !item.Realm.IsCommunity && member.PowerLevel < 25 { - return item, fmt.Errorf("you need has power level above 25 of a realm or in a community realm to post") - } - } - log.Debug().Msg("Saving post record into database...") if err := database.C.Save(&item).Error; err != nil { return item, err @@ -338,14 +329,14 @@ func NewPost(user models.Account, item models.Post) (models.Post, error) { Where("id = ?", item.ReplyID). Preload("Author"). First(&op).Error; err == nil { - if op.Author.ID != user.ID { - log.Debug().Uint("user", op.AuthorID).Msg("Notifying the original poster their post got replied...") + if op.Publisher.AccountID != nil && op.Publisher.ID != user.ID { + log.Debug().Uint("user", *op.Publisher.AccountID).Msg("Notifying the original poster their post got replied...") err = NotifyPosterAccount( - op.Author, + op.Publisher, op, "Post got replied", fmt.Sprintf("%s (%s) replied your post (#%d).", user.Nick, user.Name, op.ID), - lo.ToPtr(fmt.Sprintf("%s replied you", user.Nick)), + fmt.Sprintf("%s replied you", user.Nick), ) if err != nil { log.Error().Err(err).Msg("An error occurred when notifying user...") @@ -392,9 +383,9 @@ func EditPost(item models.Post) (models.Post, error) { } if item.Realm != nil { - item.AreaAlias = &item.Realm.Alias + item.AliasPrefix = &item.Realm.Alias } else { - item.AreaAlias = &item.Author.Name + item.AliasPrefix = &item.Publisher.Name } item, err := EnsurePostCategoriesAndTags(item) @@ -411,7 +402,7 @@ func DeletePost(item models.Post) error { return database.C.Delete(&item).Error } -func ReactPost(user models.Account, reaction models.Reaction) (bool, models.Reaction, error) { +func ReactPost(user authm.Account, reaction models.Reaction) (bool, models.Reaction, error) { var op models.Post if err := database.C. Where("id = ?", reaction.PostID). @@ -422,13 +413,13 @@ func ReactPost(user models.Account, reaction models.Reaction) (bool, models.Reac if err := database.C.Where(reaction).First(&reaction).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - if op.Author.ID != user.ID { + if op.Publisher.AccountID != nil && *op.Publisher.AccountID != user.ID { err = NotifyPosterAccount( - op.Author, + op.Publisher, op, "Post got reacted", fmt.Sprintf("%s (%s) reacted your post a %s.", user.Nick, user.Name, reaction.Symbol), - lo.ToPtr(fmt.Sprintf("%s reacted you", user.Nick)), + fmt.Sprintf("%s reacted you", user.Nick), ) if err != nil { log.Error().Err(err).Msg("An error occurred when notifying user...") @@ -437,7 +428,7 @@ func ReactPost(user models.Account, reaction models.Reaction) (bool, models.Reac err = database.C.Save(&reaction).Error if err == nil && reaction.Attitude != models.AttitudeNeutral { - _ = ModifyPosterVoteCount(op.Author, reaction.Attitude == models.AttitudePositive, 1) + _ = ModifyPosterVoteCount(op.Publisher, reaction.Attitude == models.AttitudePositive, 1) if reaction.Attitude == models.AttitudePositive { op.TotalUpvote++ @@ -454,7 +445,7 @@ func ReactPost(user models.Account, reaction models.Reaction) (bool, models.Reac } else { err = database.C.Delete(&reaction).Error if err == nil && reaction.Attitude != models.AttitudeNeutral { - _ = ModifyPosterVoteCount(op.Author, reaction.Attitude == models.AttitudePositive, -1) + _ = ModifyPosterVoteCount(op.Publisher, reaction.Attitude == models.AttitudePositive, -1) if reaction.Attitude == models.AttitudePositive { op.TotalUpvote-- diff --git a/pkg/internal/services/publishers.go b/pkg/internal/services/publishers.go index 00aa3f4..c06af24 100644 --- a/pkg/internal/services/publishers.go +++ b/pkg/internal/services/publishers.go @@ -1,26 +1,15 @@ package services import ( + "fmt" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "github.com/gofiber/fiber/v2" ) -func GetPublisher(alias string) (any, error) { - realm, err := GetRealmWithAlias(alias) - if err == nil { - return fiber.Map{ - "type": "realm", - "data": realm, - }, nil +func GetPublisher(id uint, userID uint) (models.Publisher, error) { + var publisher models.Publisher + if err := database.C.Where("id = ? AND account_id = ?", id, userID).First(&publisher).Error; err != nil { + return publisher, fmt.Errorf("unable to get publisher: %v", err) } - - var account models.Account - if err = database.C.Where("name = ?", alias).First(&account).Error; err != nil { - return nil, err - } - return fiber.Map{ - "type": "account", - "data": account, - }, nil + return publisher, nil } diff --git a/pkg/internal/services/realms.go b/pkg/internal/services/realms.go deleted file mode 100644 index 49df4bc..0000000 --- a/pkg/internal/services/realms.go +++ /dev/null @@ -1,67 +0,0 @@ -package services - -import ( - "context" - - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/dealer/pkg/proto" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" - "github.com/samber/lo" - "github.com/spf13/viper" -) - -func GetRealmWithID(id uint) (models.Realm, error) { - var realm models.Realm - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return realm, err - } - response, err := proto.NewRealmClient(pc).GetRealm(context.Background(), &proto.LookupRealmRequest{ - Id: lo.ToPtr(uint64(id)), - }) - if err != nil { - return realm, err - } - prefix := viper.GetString("database.prefix") - rm, err := hyper.LinkRealm(database.C, prefix+"realms", response) - return models.Realm{BaseRealm: rm}, err -} - -func GetRealmWithAlias(alias string) (models.Realm, error) { - var realm models.Realm - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return realm, err - } - response, err := proto.NewRealmClient(pc).GetRealm(context.Background(), &proto.LookupRealmRequest{ - Alias: &alias, - }) - if err != nil { - return realm, err - } - prefix := viper.GetString("database.prefix") - rm, err := hyper.LinkRealm(database.C, prefix+"realms", response) - return models.Realm{BaseRealm: rm}, err -} - -func GetRealmMember(realmId uint, userId uint) (*proto.RealmMemberInfo, error) { - var realm models.Realm - if err := database.C.Where("id = ?", realmId).First(&realm).Error; err != nil { - return nil, err - } - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return nil, err - } - response, err := proto.NewRealmClient(pc).GetRealmMember(context.Background(), &proto.RealmMemberLookupRequest{ - RealmId: lo.ToPtr(uint64(realm.ID)), - UserId: lo.ToPtr(uint64(userId)), - }) - if err != nil { - return nil, err - } else { - return response, nil - } -} diff --git a/pkg/internal/services/subscriptions.go b/pkg/internal/services/subscriptions.go index 7aec6cc..94b15ee 100644 --- a/pkg/internal/services/subscriptions.go +++ b/pkg/internal/services/subscriptions.go @@ -1,20 +1,18 @@ package services import ( - "context" "errors" "fmt" - "time" - - "git.solsynth.dev/hydrogen/dealer/pkg/hyper" - "git.solsynth.dev/hydrogen/dealer/pkg/proto" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" "git.solsynth.dev/hydrogen/interactive/pkg/internal/models" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" + "git.solsynth.dev/hypernet/pusher/pkg/pushkit" "gorm.io/gorm" ) -func GetSubscriptionOnUser(user models.Account, target models.Account) (*models.Subscription, error) { +func GetSubscriptionOnUser(user authm.Account, target models.Publisher) (*models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -25,7 +23,7 @@ func GetSubscriptionOnUser(user models.Account, target models.Account) (*models. return &subscription, nil } -func GetSubscriptionOnTag(user models.Account, target models.Tag) (*models.Subscription, error) { +func GetSubscriptionOnTag(user authm.Account, target models.Tag) (*models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -36,7 +34,7 @@ func GetSubscriptionOnTag(user models.Account, target models.Tag) (*models.Subsc return &subscription, nil } -func GetSubscriptionOnCategory(user models.Account, target models.Category) (*models.Subscription, error) { +func GetSubscriptionOnCategory(user authm.Account, target models.Category) (*models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -47,18 +45,7 @@ func GetSubscriptionOnCategory(user models.Account, target models.Category) (*mo return &subscription, nil } -func GetSubscriptionOnRealm(user models.Account, target models.Realm) (*models.Subscription, error) { - var subscription models.Subscription - if err := database.C.Where("follower_id = ? AND realm_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil - } - return nil, fmt.Errorf("unable to get subscription: %v", err) - } - return &subscription, nil -} - -func SubscribeToUser(user models.Account, target models.Account) (models.Subscription, error) { +func SubscribeToUser(user authm.Account, target models.Publisher) (models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { @@ -75,7 +62,7 @@ func SubscribeToUser(user models.Account, target models.Account) (models.Subscri return subscription, err } -func SubscribeToTag(user models.Account, target models.Tag) (models.Subscription, error) { +func SubscribeToTag(user authm.Account, target models.Tag) (models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { @@ -92,7 +79,7 @@ func SubscribeToTag(user models.Account, target models.Tag) (models.Subscription return subscription, err } -func SubscribeToCategory(user models.Account, target models.Category) (models.Subscription, error) { +func SubscribeToCategory(user authm.Account, target models.Category) (models.Subscription, error) { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { @@ -109,24 +96,7 @@ func SubscribeToCategory(user models.Account, target models.Category) (models.Su return subscription, err } -func SubscribeToRealm(user models.Account, target models.Realm) (models.Subscription, error) { - var subscription models.Subscription - if err := database.C.Where("follower_id = ? AND realm_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { - if !errors.Is(err, gorm.ErrRecordNotFound) { - return subscription, fmt.Errorf("subscription already exists") - } - } - - subscription = models.Subscription{ - FollowerID: user.ID, - RealmID: &target.ID, - } - - err := database.C.Save(&subscription).Error - return subscription, err -} - -func UnsubscribeFromUser(user models.Account, target models.Account) error { +func UnsubscribeFromUser(user authm.Account, target models.Publisher) error { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND account_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -139,7 +109,7 @@ func UnsubscribeFromUser(user models.Account, target models.Account) error { return err } -func UnsubscribeFromTag(user models.Account, target models.Tag) error { +func UnsubscribeFromTag(user authm.Account, target models.Tag) error { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND tag_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -152,7 +122,7 @@ func UnsubscribeFromTag(user models.Account, target models.Tag) error { return err } -func UnsubscribeFromCategory(user models.Account, target models.Category) error { +func UnsubscribeFromCategory(user authm.Account, target models.Category) error { var subscription models.Subscription if err := database.C.Where("follower_id = ? AND category_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { @@ -165,20 +135,7 @@ func UnsubscribeFromCategory(user models.Account, target models.Category) error return err } -func UnsubscribeFromRealm(user models.Account, target models.Realm) error { - var subscription models.Subscription - if err := database.C.Where("follower_id = ? AND realm_id = ?", user.ID, target.ID).First(&subscription).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("subscription does not exist") - } - return fmt.Errorf("unable to check subscription is exists or not: %v", err) - } - - err := database.C.Delete(&subscription).Error - return err -} - -func NotifyUserSubscription(poster models.Account, content string, title *string) error { +func NotifyUserSubscription(poster models.Publisher, content string, title *string) error { var subscriptions []models.Subscription if err := database.C.Where("account_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil { return fmt.Errorf("unable to get subscriptions: %v", err) @@ -197,30 +154,18 @@ func NotifyUserSubscription(poster models.Account, content string, title *string userIDs = append(userIDs, uint64(subscription.Follower.ID)) } - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - _, err = proto.NewNotifierClient(pc).NotifyUserBatch(ctx, &proto.NotifyUserBatchRequest{ - UserId: userIDs, - Notify: &proto.NotifyRequest{ - Topic: "interactive.subscription", - Title: nTitle, - Subtitle: &nSubtitle, - Body: body, - IsRealtime: false, - IsForcePush: true, - }, + err := authkit.NotifyUserBatch(gap.Nx, userIDs, pushkit.Notification{ + Topic: "interactive.subscription", + Title: nTitle, + Subtitle: nSubtitle, + Body: body, + Priority: 3, }) return err } -func NotifyTagSubscription(poster models.Tag, og models.Account, content string, title *string) error { +func NotifyTagSubscription(poster models.Tag, og models.Publisher, content string, title *string) error { var subscriptions []models.Subscription if err := database.C.Where("tag_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil { return fmt.Errorf("unable to get subscriptions: %v", err) @@ -239,30 +184,18 @@ func NotifyTagSubscription(poster models.Tag, og models.Account, content string, userIDs = append(userIDs, uint64(subscription.Follower.ID)) } - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - _, err = proto.NewNotifierClient(pc).NotifyUserBatch(ctx, &proto.NotifyUserBatchRequest{ - UserId: userIDs, - Notify: &proto.NotifyRequest{ - Topic: "interactive.subscription", - Title: nTitle, - Subtitle: &nSubtitle, - Body: body, - IsRealtime: false, - IsForcePush: true, - }, + err := authkit.NotifyUserBatch(gap.Nx, userIDs, pushkit.Notification{ + Topic: "interactive.subscription", + Title: nTitle, + Subtitle: nSubtitle, + Body: body, + Priority: 3, }) return err } -func NotifyCategorySubscription(poster models.Category, og models.Account, content string, title *string) error { +func NotifyCategorySubscription(poster models.Category, og models.Publisher, content string, title *string) error { var subscriptions []models.Subscription if err := database.C.Where("category_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil { return fmt.Errorf("unable to get subscriptions: %v", err) @@ -281,66 +214,12 @@ func NotifyCategorySubscription(poster models.Category, og models.Account, conte userIDs = append(userIDs, uint64(subscription.Follower.ID)) } - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - _, err = proto.NewNotifierClient(pc).NotifyUserBatch(ctx, &proto.NotifyUserBatchRequest{ - UserId: userIDs, - Notify: &proto.NotifyRequest{ - Topic: "interactive.subscription", - Title: nTitle, - Subtitle: &nSubtitle, - Body: body, - IsRealtime: false, - IsForcePush: true, - }, - }) - - return err -} - -func NotifyRealmSubscription(poster models.Realm, og models.Account, content string, title *string) error { - var subscriptions []models.Subscription - if err := database.C.Where("realm_id = ?", poster.ID).Preload("Follower").Find(&subscriptions).Error; err != nil { - return fmt.Errorf("unable to get subscriptions: %v", err) - } - - nTitle := fmt.Sprintf("New post in %s by %s (%s)", poster.Name, og.Nick, og.Name) - nSubtitle := "From your subscription" - - body := TruncatePostContentShort(content) - if title != nil { - body = fmt.Sprintf("%s\n%s", *title, body) - } - - userIDs := make([]uint64, 0, len(subscriptions)) - for _, subscription := range subscriptions { - userIDs = append(userIDs, uint64(subscription.Follower.ID)) - } - - pc, err := gap.H.GetServiceGrpcConn(hyper.ServiceTypeAuthProvider) - if err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - _, err = proto.NewNotifierClient(pc).NotifyUserBatch(ctx, &proto.NotifyUserBatchRequest{ - UserId: userIDs, - Notify: &proto.NotifyRequest{ - Topic: "interactive.subscription", - Title: nTitle, - Subtitle: &nSubtitle, - Body: body, - IsRealtime: false, - IsForcePush: true, - }, + err := authkit.NotifyUserBatch(gap.Nx, userIDs, pushkit.Notification{ + Topic: "interactive.subscription", + Title: nTitle, + Subtitle: nSubtitle, + Body: body, + Priority: 3, }) return err diff --git a/pkg/main.go b/pkg/main.go index fd552a8..19394e6 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -1,15 +1,18 @@ package main import ( + "fmt" + pkg "git.solsynth.dev/hydrogen/interactive/pkg/internal" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + "github.com/fatih/color" "os" "os/signal" "syscall" - pkg "git.solsynth.dev/hydrogen/interactive/pkg/internal" "git.solsynth.dev/hydrogen/interactive/pkg/internal/database" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/gap" "git.solsynth.dev/hydrogen/interactive/pkg/internal/grpc" - "git.solsynth.dev/hydrogen/interactive/pkg/internal/server" + "git.solsynth.dev/hydrogen/interactive/pkg/internal/http" "git.solsynth.dev/hydrogen/interactive/pkg/internal/services" "github.com/robfig/cron/v3" "github.com/rs/zerolog" @@ -23,6 +26,12 @@ func init() { } func main() { + // Booting screen + fmt.Println(color.YellowString(" ___ _ _ _\n|_ _|_ __ | |_ ___ _ __ __ _ ___| |_(_)_ _____\n | || '_ \\| __/ _ \\ '__/ _` |/ __| __| \\ \\ / / _ \\\n | || | | | || __/ | | (_| | (__| |_| |\\ V / __/\n|___|_| |_|\\__\\___|_| \\__,_|\\___|\\__|_| \\_/ \\___|")) + fmt.Printf("%s v%s\n", color.New(color.FgHiYellow).Add(color.Bold).Sprintf("Hypernet.Interactive"), pkg.AppVersion) + fmt.Printf("The social networking service in Hypernet\n") + color.HiBlack("=====================================================\n") + // Configure settings viper.AddConfigPath(".") viper.AddConfigPath("..") @@ -34,38 +43,40 @@ func main() { log.Panic().Err(err).Msg("An error occurred when loading settings.") } + // Connect to nexus + if err := gap.InitializeToNexus(); err != nil { + log.Fatal().Err(err).Msg("An error occurred when connecting to nexus...") + } + + // Load keypair + if reader, err := sec.NewInternalTokenReader(viper.GetString("security.internal_public_key")); err != nil { + log.Error().Err(err).Msg("An error occurred when reading internal public key for jwt. Authentication related features will be disabled.") + } else { + http.IReader = reader + log.Info().Msg("Internal jwt public key loaded.") + } + // Connect to database - if err := database.NewSource(); err != nil { + if err := database.NewGorm(); err != nil { log.Fatal().Err(err).Msg("An error occurred when connect to database.") } else if err := database.RunMigration(database.C); err != nil { log.Fatal().Err(err).Msg("An error occurred when running database auto migration.") } - // Connect other services - if err := gap.RegisterService(); err != nil { - log.Fatal().Err(err).Msg("An error occurred when connecting to consul...") - } - // Configure timed tasks quartz := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(&log.Logger))) quartz.AddFunc("@every 60m", services.DoAutoDatabaseCleanup) quartz.Start() // Server - server.NewServer() - go server.Listen() + go http.NewServer().Listen() - grpc.NewGRPC() - go grpc.ListenGRPC() + go grpc.NewGrpc().Listen() // Messages - log.Info().Msgf("Interactive v%s is started...", pkg.AppVersion) - quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit - log.Info().Msgf("Interactive v%s is quitting...", pkg.AppVersion) - quartz.Stop() } diff --git a/settings.toml b/settings.toml index 2d9bf30..1e532e2 100644 --- a/settings.toml +++ b/settings.toml @@ -1,23 +1,13 @@ id = "interactive01" -bind = "0.0.0.0:8445" -grpc_bind = "0.0.0.0:7445" -domain = "im.solsynth.dev" -secret = "LtTjzAGFLshwXhN4ZD4nG5KlMv1MWcsvfv03TSZYnT1VhiAnLIZFTnHUwR0XhGgi" +bind = "0.0.0.0:8005" +grpc_bind = "0.0.0.0:7005" + +nexus_addr = "localhost:7001" [debug] database = true print_routes = false -[dealer] -addr = "127.0.0.1:7442" - [security] -cookie_domain = "localhost" -cookie_samesite = "Lax" -access_token_duration = 300 -refresh_token_duration = 2592000 - -[database] -dsn = "host=localhost user=postgres password=password dbname=hy_interactive port=5432 sslmode=disable" -prefix = "interactive_" +internal_public_key = "keys/internal_public_key.pem"