From 4261a542cab1e885e2083aa19ed472c398eaec69 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Mon, 21 Sep 2026 11:08:41 +0800 Subject: [PATCH] fix(#328): filter manual PDD association by owned devices --- server/app/goauto/product/handler.go | 12 +++++-- server/app/goauto/product/service.go | 12 ++++--- server/app/goauto/product/service_test.go | 38 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/server/app/goauto/product/handler.go b/server/app/goauto/product/handler.go index 436d676..ad2e3a1 100644 --- a/server/app/goauto/product/handler.go +++ b/server/app/goauto/product/handler.go @@ -10,6 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-admin-team/go-admin-core/sdk/pkg" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" "gorm.io/gorm" ) @@ -30,9 +31,16 @@ func (handler Handler) List(c *gin.Context) { if !ok { return } - response, err := service.List(c.Request.Context(), ListRequest{ + request := ListRequest{ Page: page, PageSize: pageSize, GoodsID: c.Query("goodsId"), Keyword: c.Query("keyword"), Status: strings.TrimSpace(c.Query("status")), - }) + } + claims := jwt.ExtractClaims(c) + if role, _ := claims["rolekey"].(string); role != "admin" { + id, _ := claims["identity"].(float64) + owner := uint64(id) + request.CollectionOwnerUserID = &owner + } + response, err := service.List(c.Request.Context(), request) if err != nil { writeError(c, err) return diff --git a/server/app/goauto/product/service.go b/server/app/goauto/product/service.go index 5d6402c..fce8b9c 100644 --- a/server/app/goauto/product/service.go +++ b/server/app/goauto/product/service.go @@ -64,10 +64,11 @@ type UpdateRequest struct { } type ListRequest struct { - Page, PageSize int - Keyword string - GoodsID string - Status string + Page, PageSize int + Keyword string + GoodsID string + Status string + CollectionOwnerUserID *uint64 } type ProductView struct { @@ -266,6 +267,9 @@ func (service *Service) List(ctx context.Context, request ListRequest) (ListResp } query = query.Where("status = ?", request.Status) } + if request.CollectionOwnerUserID != nil { + query = query.Where("EXISTS (SELECT 1 FROM collection_task ct JOIN agent_device ad ON ad.id = ct.device_id WHERE ct.pdd_product_id = pdd_product.id AND ct.source = ? AND ct.status IN ? AND ad.owner_user_id = ?)", models.CollectionTaskSourceAgentCurrentPage, []string{models.TaskStatusCompleted, models.TaskStatusCompletedPartial}, *request.CollectionOwnerUserID) + } var total int64 if err := query.Count(&total).Error; err != nil { return ListResponse{}, internalError(err) diff --git a/server/app/goauto/product/service_test.go b/server/app/goauto/product/service_test.go index 8602bfe..98e6c09 100644 --- a/server/app/goauto/product/service_test.go +++ b/server/app/goauto/product/service_test.go @@ -205,6 +205,44 @@ func TestListMarksProductsUnavailableForCollection(t *testing.T) { } } +func TestListFiltersManualAssociationProductsByOwnedCollectionDevice(t *testing.T) { + db := openProductDatabase(t) + service := NewService(db) + rule := models.CollectionRule{Name: "owned-rule", ContentJSON: `{}`} + if err := db.Create(&rule).Error; err != nil { + t.Fatal(err) + } + products := []models.PDDProduct{{GoodsID: "910001", URL: "https://mobile.yangkeduo.com/goods.html?goods_id=910001", Status: "active"}, {GoodsID: "910002", URL: "https://mobile.yangkeduo.com/goods.html?goods_id=910002", Status: "active"}, {GoodsID: "910003", URL: "https://mobile.yangkeduo.com/goods.html?goods_id=910003", Status: "active"}} + if err := db.Create(&products).Error; err != nil { + t.Fatal(err) + } + owned := models.AgentDevice{InstallID: "owned-manual-list", Name: "owned", Manufacturer: "test", Model: "test", AndroidVersion: "14", AgentVersion: "1", PDDVersion: "1", Status: models.DeviceStatusOffline, TokenDigest: "owned-digest", TokenIssuedAt: time.Now(), OwnerUserID: ptrUint64(41)} + other := models.AgentDevice{InstallID: "other-manual-list", Name: "other", Manufacturer: "test", Model: "test", AndroidVersion: "14", AgentVersion: "1", PDDVersion: "1", Status: models.DeviceStatusOffline, TokenDigest: "other-digest", TokenIssuedAt: time.Now(), OwnerUserID: ptrUint64(42)} + if err := db.Create(&owned).Error; err != nil { + t.Fatal(err) + } + if err := db.Create(&other).Error; err != nil { + t.Fatal(err) + } + for _, task := range []models.CollectionTask{{PDDProductID: &products[0].ID, DeviceID: &owned.ID, Source: models.CollectionTaskSourceAgentCurrentPage, Status: models.TaskStatusCompleted}, {PDDProductID: &products[1].ID, DeviceID: &other.ID, Source: models.CollectionTaskSourceAgentCurrentPage, Status: models.TaskStatusCompleted}, {PDDProductID: &products[2].ID, DeviceID: &owned.ID, Source: models.CollectionTaskSourceAdmin, Status: models.TaskStatusCompleted}} { + task.RuleID = rule.ID + task.URLSnapshot = products[0].URL + task.RuleSnapshot = rule.ContentJSON + if err := db.Create(&task).Error; err != nil { + t.Fatal(err) + } + } + got, err := service.List(context.Background(), ListRequest{Page: 1, PageSize: 20, CollectionOwnerUserID: ptrUint64(41)}) + if err != nil { + t.Fatal(err) + } + if len(got.Items) != 1 || got.Items[0].GoodsID != products[0].GoodsID { + t.Fatalf("unexpected owned products: %+v", got.Items) + } +} + +func ptrUint64(value uint64) *uint64 { return &value } + func TestListDisablesCollectionWhenNoRuleExists(t *testing.T) { db := openProductDatabase(t) product := models.PDDProduct{GoodsID: "444444", URL: "https://mobile.yangkeduo.com/goods.html?goods_id=444444", Status: "active"}