From 3cd102046ae2992ba3035826ae45cf5755f0447c Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 29 Mar 2025 22:38:43 +0800 Subject: [PATCH] :alembic: Testing with the new post listing v2 --- go.mod | 11 +- go.sum | 27 ++-- pkg/internal/http/api/categories_api.go | 2 +- pkg/internal/http/api/index.go | 1 + pkg/internal/http/api/posts_api.go | 48 ++++++- pkg/internal/http/api/recommendation_api.go | 2 +- pkg/internal/http/api/replies_api.go | 4 +- pkg/internal/http/api/tags_api.go | 2 +- pkg/internal/models/publishers.go | 8 +- pkg/internal/services/queries/posts.go | 136 ++++++++++++++++++++ 10 files changed, 220 insertions(+), 21 deletions(-) create mode 100644 pkg/internal/services/queries/posts.go diff --git a/go.mod b/go.mod index 49a15b1..3ac9deb 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,10 @@ go 1.23.2 require ( git.solsynth.dev/hypernet/insight v0.0.0-20250129172551-974266b2c1d2 git.solsynth.dev/hypernet/nexus v0.0.0-20250329075932-d5422ab5b04c - git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47 - git.solsynth.dev/hypernet/passport v0.0.0-20250316041213-ecaace561632 + git.solsynth.dev/hypernet/paperclip v0.0.0-20250329141722-820d7a9f42e6 + git.solsynth.dev/hypernet/passport v0.0.0-20250329100405-b327e0806279 git.solsynth.dev/hypernet/pusher v0.0.0-20250216145944-5fb769823a88 - git.solsynth.dev/hypernet/wallet v0.0.0-20250129150034-87b94cdb5488 + git.solsynth.dev/hypernet/wallet v0.0.0-20250323095812-468cd655f886 github.com/fatih/color v1.18.0 github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581 github.com/go-playground/validator/v10 v10.22.1 @@ -33,6 +33,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/eko/gocache/lib/v4 v4.2.0 // indirect github.com/eko/gocache/store/redis/v4 v4.2.2 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect @@ -54,11 +55,14 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // 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.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.70 // 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 @@ -73,6 +77,7 @@ require ( github.com/prometheus/procfs v0.13.0 // indirect github.com/redis/go-redis/v9 v9.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/xid v1.5.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 diff --git a/go.sum b/go.sum index 52ac0cb..96a33df 100644 --- a/go.sum +++ b/go.sum @@ -2,18 +2,18 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.solsynth.dev/hypernet/insight v0.0.0-20250129172551-974266b2c1d2 h1:dPBdssDIb+SqkAYlZgv80iftkfiijpMBCKe/6o4jwuA= git.solsynth.dev/hypernet/insight v0.0.0-20250129172551-974266b2c1d2/go.mod h1:NKSTeRc1mgg726iaCLEBoYEcVroIrGU5w2rnGf92LWE= -git.solsynth.dev/hypernet/nexus v0.0.0-20250329053929-488793a2dc56 h1:SnT9NVcXQ1WDka9kKAA+lH/r2UJouND7FDugu4ZZwLc= -git.solsynth.dev/hypernet/nexus v0.0.0-20250329053929-488793a2dc56/go.mod h1:5tk62VQ1DcbR0EAN2jAOqYxHiegUPEC805JlfQ/G19I= git.solsynth.dev/hypernet/nexus v0.0.0-20250329075932-d5422ab5b04c h1:XgdTgJxSAQuCbiG15hN5pY6chzcz8sX3Onm2itS+Ufs= git.solsynth.dev/hypernet/nexus v0.0.0-20250329075932-d5422ab5b04c/go.mod h1:5tk62VQ1DcbR0EAN2jAOqYxHiegUPEC805JlfQ/G19I= -git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47 h1:fvu+bNKPTNtQocssnKbEZ66MqR0iBfAxY3HwlqnmYyE= -git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47/go.mod h1:jvxq2qftz2v72x+24+cTFJdQKr9eHQTdk3KVR7cx36s= -git.solsynth.dev/hypernet/passport v0.0.0-20250316041213-ecaace561632 h1:rO0aFXOdNIHUx13UE3Q2RjeTdgouIOCMYlOycgdDUNg= -git.solsynth.dev/hypernet/passport v0.0.0-20250316041213-ecaace561632/go.mod h1:+G1SHAmVGGjsmuCllZpH3jgpYGaYu/JzcXdgj6RQTOY= +git.solsynth.dev/hypernet/paperclip v0.0.0-20250329095638-8f91649d2570 h1:Nmm7zNpE/9ni/JFRO331D+w0pGz6IBKiNCSyFFbqWFA= +git.solsynth.dev/hypernet/paperclip v0.0.0-20250329095638-8f91649d2570/go.mod h1:TdFsd/W3e04GAFVOWXBP9acSYF+YpmSeSdocnvt/4IY= +git.solsynth.dev/hypernet/paperclip v0.0.0-20250329141722-820d7a9f42e6 h1:n7MgY8/TRJZXO4EJKmRqmzJQmE0E0X02Vf/pNJjRfms= +git.solsynth.dev/hypernet/paperclip v0.0.0-20250329141722-820d7a9f42e6/go.mod h1:TdFsd/W3e04GAFVOWXBP9acSYF+YpmSeSdocnvt/4IY= +git.solsynth.dev/hypernet/passport v0.0.0-20250329100405-b327e0806279 h1:7eL9za4zGsoKImiCXkpGFdXcSYhdegSRVsXfBJq7Q5I= +git.solsynth.dev/hypernet/passport v0.0.0-20250329100405-b327e0806279/go.mod h1:lbE/HrtMsnplOGvkg1JNjJL6DiXAnYczayxqN72UAJc= git.solsynth.dev/hypernet/pusher v0.0.0-20250216145944-5fb769823a88 h1:2HEENe9KUrdaJeNBzx9lsuXQGyzWqCgnLTKQnr8xFr8= git.solsynth.dev/hypernet/pusher v0.0.0-20250216145944-5fb769823a88/go.mod h1:ildzMtLagNsLK0Rkw4Hgk2TrrwqZnjwJIUx0MNZwcDY= -git.solsynth.dev/hypernet/wallet v0.0.0-20250129150034-87b94cdb5488 h1:/9Ol+PfDQFAYtHo0kk6sxqiEsZ6epb6yUEsZJxy14Mk= -git.solsynth.dev/hypernet/wallet v0.0.0-20250129150034-87b94cdb5488/go.mod h1:jd1MTBI5NPHne22nq7nR7kyl4iYb9kV2A+tpXi7HOYY= +git.solsynth.dev/hypernet/wallet v0.0.0-20250323095812-468cd655f886 h1:rVssXF8jZ64ctAfzlCgIgF22NCT9VAPAVxrwlcItx3s= +git.solsynth.dev/hypernet/wallet v0.0.0-20250323095812-468cd655f886/go.mod h1:rmomNGQ6RBSp8TpZGA8tFr5M54AL2NADJ/1n0MfrIRM= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= @@ -33,6 +33,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eko/gocache/lib/v4 v4.2.0 h1:MNykyi5Xw+5Wu3+PUrvtOCaKSZM1nUSVftbzmeC7Yuw= github.com/eko/gocache/lib/v4 v4.2.0/go.mod h1:7ViVmbU+CzDHzRpmB4SXKyyzyuJ8A3UW3/cszpcqB4M= github.com/eko/gocache/store/redis/v4 v4.2.2 h1:Thw31fzGuH3WzJywsdbMivOmP550D6JS7GDHhvCJPA0= @@ -104,6 +106,9 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -125,6 +130,10 @@ github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOj github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.70 h1:1u9NtMgfK1U42kUxcsl5v0yj6TEOPR497OAQxpJnn2g= +github.com/minio/minio-go/v7 v7.0.70/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -165,6 +174,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -240,6 +250,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= diff --git a/pkg/internal/http/api/categories_api.go b/pkg/internal/http/api/categories_api.go index 908e726..b12484a 100644 --- a/pkg/internal/http/api/categories_api.go +++ b/pkg/internal/http/api/categories_api.go @@ -20,7 +20,7 @@ func getCategory(c *fiber.Ctx) error { } func listCategories(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) probe := c.Query("probe") diff --git a/pkg/internal/http/api/index.go b/pkg/internal/http/api/index.go index 28ebeba..fd02cd2 100644 --- a/pkg/internal/http/api/index.go +++ b/pkg/internal/http/api/index.go @@ -59,6 +59,7 @@ func MapControllers(app *fiber.App, baseURL string) { posts := api.Group("/posts").Name("Posts API") { posts.Get("/", listPost) + posts.Get("/v2", listPostV2) posts.Get("/search", searchPost) posts.Get("/minimal", listPostMinimal) posts.Get("/drafts", listDraftPost) diff --git a/pkg/internal/http/api/posts_api.go b/pkg/internal/http/api/posts_api.go index 3d8d515..5e71a6b 100644 --- a/pkg/internal/http/api/posts_api.go +++ b/pkg/internal/http/api/posts_api.go @@ -15,6 +15,7 @@ import ( "git.solsynth.dev/hypernet/interactive/pkg/internal/http/exts" "git.solsynth.dev/hypernet/interactive/pkg/internal/models" "git.solsynth.dev/hypernet/interactive/pkg/internal/services" + "git.solsynth.dev/hypernet/interactive/pkg/internal/services/queries" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) @@ -63,7 +64,7 @@ func getPost(c *fiber.Ctx) error { } func searchPost(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) tx := database.C @@ -113,7 +114,7 @@ func searchPost(c *fiber.Ctx) error { } func listPost(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) tx := database.C @@ -153,8 +154,47 @@ func listPost(c *fiber.Ctx) error { }) } +func listPostV2(c *fiber.Ctx) error { + take := c.QueryInt("take", 10) + offset := c.QueryInt("offset", 0) + + tx := database.C + + var err error + if tx, err = services.UniversalPostFilter(c, tx); err != nil { + return err + } + + var userId *uint + if user, authenticated := c.Locals("user").(authm.Account); authenticated { + userId = &user.ID + } + + countTx := tx + count, err := services.CountPost(countTx) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + items, err := queries.ListPostV2(tx, take, offset, "published_at DESC", userId) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + if c.QueryBool("truncate", true) { + for _, item := range items { + item = services.TruncatePostContent(item) + } + } + + return c.JSON(fiber.Map{ + "count": count, + "data": items, + }) +} + func listPostMinimal(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) tx := database.C @@ -190,7 +230,7 @@ func listPostMinimal(c *fiber.Ctx) error { } func listDraftPost(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) if err := sec.EnsureAuthenticated(c); err != nil { diff --git a/pkg/internal/http/api/recommendation_api.go b/pkg/internal/http/api/recommendation_api.go index 1f2c2de..7cdd204 100644 --- a/pkg/internal/http/api/recommendation_api.go +++ b/pkg/internal/http/api/recommendation_api.go @@ -46,7 +46,7 @@ func listRecommendation(c *fiber.Ctx) error { } func listRecommendationShuffle(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) tx := database.C diff --git a/pkg/internal/http/api/replies_api.go b/pkg/internal/http/api/replies_api.go index 4b58cec..c0b73da 100644 --- a/pkg/internal/http/api/replies_api.go +++ b/pkg/internal/http/api/replies_api.go @@ -11,7 +11,7 @@ import ( ) func listPostReplies(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) tx := database.C @@ -59,7 +59,7 @@ func listPostReplies(c *fiber.Ctx) error { } func listPostFeaturedReply(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) take = max(1, min(take, 3)) var userId *uint diff --git a/pkg/internal/http/api/tags_api.go b/pkg/internal/http/api/tags_api.go index 9c2f462..4ee5e92 100644 --- a/pkg/internal/http/api/tags_api.go +++ b/pkg/internal/http/api/tags_api.go @@ -18,7 +18,7 @@ func getTag(c *fiber.Ctx) error { } func listTags(c *fiber.Ctx) error { - take := c.QueryInt("take", 0) + take := c.QueryInt("take", 10) offset := c.QueryInt("offset", 0) probe := c.Query("probe") diff --git a/pkg/internal/models/publishers.go b/pkg/internal/models/publishers.go index 4357270..7a5009f 100644 --- a/pkg/internal/models/publishers.go +++ b/pkg/internal/models/publishers.go @@ -1,6 +1,9 @@ package models -import "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" +import ( + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + "git.solsynth.dev/hypernet/passport/pkg/authkit/models" +) const ( PublisherTypePersonal = iota @@ -26,4 +29,7 @@ type Publisher struct { RealmID *uint `json:"realm_id"` AccountID *uint `json:"account_id"` + + Account models.Account `gorm:"-"` + Realm models.Realm `json:"-"` } diff --git a/pkg/internal/services/queries/posts.go b/pkg/internal/services/queries/posts.go new file mode 100644 index 0000000..f0e983f --- /dev/null +++ b/pkg/internal/services/queries/posts.go @@ -0,0 +1,136 @@ +package queries + +import ( + "fmt" + + "git.solsynth.dev/hypernet/interactive/pkg/internal/database" + "git.solsynth.dev/hypernet/interactive/pkg/internal/gap" + "git.solsynth.dev/hypernet/interactive/pkg/internal/models" + "git.solsynth.dev/hypernet/interactive/pkg/internal/services" + "git.solsynth.dev/hypernet/paperclip/pkg/filekit" + fmodels "git.solsynth.dev/hypernet/paperclip/pkg/filekit/models" + "git.solsynth.dev/hypernet/passport/pkg/authkit" + amodels "git.solsynth.dev/hypernet/passport/pkg/authkit/models" + "github.com/samber/lo" + "gorm.io/gorm" +) + +// This api still is experimental and finally with replace the old one +// Some changes between ListPost and ListPostV2: +// - Post reply to and repost to are not included +func ListPostV2(tx *gorm.DB, take int, offset int, order any, user *uint) ([]models.Post, error) { + if take > 100 { + take = 100 + } + + if take >= 0 { + tx = tx.Limit(take) + } + if offset >= 0 { + tx = tx.Offset(offset) + } + + tx = tx.Preload("Tags"). + Preload("Categories"). + Preload("Publisher") + + // Fetch posts + var posts []models.Post + if err := tx.Order(order).Find(&posts).Error; err != nil { + return nil, err + } + + // If no posts found, return early + if len(posts) == 0 { + return posts, nil + } + + // Collect post IDs + idx := make([]uint, len(posts)) + itemMap := make(map[uint]*models.Post, len(posts)) + for i, item := range posts { + idx[i] = item.ID + itemMap[item.ID] = &item + } + + // Batch load reactions + if mapping, err := services.BatchListPostReactions(database.C.Where("post_id IN ?", idx), "post_id"); err != nil { + return posts, err + } else { + for postID, reactions := range mapping { + if post, exists := itemMap[postID]; exists { + post.Metric.ReactionList = reactions + } + } + } + + // Batch load reply counts efficiently + var replies []struct { + PostID uint + Count int64 + } + if err := database.C.Model(&models.Post{}). + Select("reply_id as post_id, COUNT(id) as count"). + Where("reply_id IN (?)", idx). + Group("post_id"). + Find(&replies).Error; err != nil { + return posts, err + } + for _, info := range replies { + if post, exists := itemMap[info.PostID]; exists { + post.Metric.ReplyCount = info.Count + } + } + + // Batch load some metadata + var attachmentsRid []string + var usersId []uint + + // Scan records that can be load egearly + for _, info := range posts { + if val, ok := info.Body["attachments"].([]string); ok && len(val) > 0 { + if info.Publisher.AccountID != nil { + usersId = append(usersId, *info.Publisher.AccountID) + } + attachmentsRid = append(attachmentsRid, val...) + } + } + + // Batch load attachments + attachmentsRid = lo.Uniq(attachmentsRid) + attachments, err := filekit.ListAttachment(gap.Nx, attachmentsRid) + if err != nil { + return posts, fmt.Errorf("failed to load attachments: %v", err) + } + + // Batch load publisher users + usersId = lo.Uniq(usersId) + users, err := authkit.ListUser(gap.Nx, usersId) + if err != nil { + return posts, fmt.Errorf("failed to load users: %v", err) + } + + // Putting information back to data + for _, item := range posts { + var this []fmodels.Attachment + if val, ok := item.Body["attachments"].([]string); ok && len(val) > 0 { + this = lo.Filter(attachments, func(item fmodels.Attachment, _ int) bool { + return lo.Contains(val, item.Rid) + }) + } + item.Body["attachments"] = this + item.Publisher.Account = lo.FindOrElse(users, amodels.Account{}, func(acc amodels.Account) bool { + if item.Publisher.AccountID == nil { + return false + } + return acc.ID == *item.Publisher.AccountID + }) + } + + // Add post views for the user + if user != nil { + services.AddPostViews(posts, *user) + } + + return posts, nil +}