From db1dde30dea75f62e79b10cf37a7101e26532b48 Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Thu, 2 Jan 2025 18:24:43 +0500 Subject: [PATCH 1/2] feat: add time-based filtering for workspace bounty cards --- db/db.go | 10 ++- handlers/bounty_test.go | 145 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/db/db.go b/db/db.go index faa7369d0..cd934d31a 100644 --- a/db/db.go +++ b/db/db.go @@ -1987,6 +1987,14 @@ func (db database) GetWorkspaceBountyCardsData(r *http.Request) []NewBounty { limitQuery := "" searchQuery := "" workspaceQuery := "" + timeFilterQuery := "" + + timeFilterQuery = ` + AND ( + (NOT paid AND updated > NOW() - INTERVAL '4 weeks') + OR (paid AND updated > NOW() - INTERVAL '2 weeks') + OR updated IS NULL -- Preserve existing records without updated timestamp + )` if sortBy != "" && direction != "" { orderQuery = "ORDER BY " + sortBy + " " + direction @@ -2007,7 +2015,7 @@ func (db database) GetWorkspaceBountyCardsData(r *http.Request) []NewBounty { } query := "SELECT * FROM public.bounty" - allQuery := query + " " + workspaceQuery + " " + searchQuery + " " + orderQuery + " " + limitQuery + allQuery := query + " " + workspaceQuery + timeFilterQuery + " " + searchQuery + " " + orderQuery + " " + limitQuery ms := []NewBounty{} db.db.Raw(allQuery).Scan(&ms) diff --git a/handlers/bounty_test.go b/handlers/bounty_test.go index 1ed4c7c8e..e115592dd 100644 --- a/handlers/bounty_test.go +++ b/handlers/bounty_test.go @@ -3028,6 +3028,9 @@ func TestGetWorkspaceBountyCards(t *testing.T) { Price: 2000, } + fiveWeeksAgo := now.Add(-5 * 7 * 24 * time.Hour) + threeWeeksAgo := now.Add(-3 * 7 * 24 * time.Hour) + t.Run("should only get public bounty", func(t *testing.T) { db.TestDB.DeleteAllBounties() _, err := db.TestDB.CreateOrEditBounty(publicBounty) @@ -3069,4 +3072,146 @@ func TestGetWorkspaceBountyCards(t *testing.T) { assert.Equal(t, 1, len(response)) assert.Equal(t, "Private Bounty", response[0].Title) }) + + t.Run("should include recent unpaid bounty", func(t *testing.T) { + db.TestDB.DeleteAllBounties() + + recentUnpaidBounty := db.NewBounty{ + ID: 1, + Type: "coding", + Title: "Recent Unpaid", + Description: "Test Description", + WorkspaceUuid: workspace.Uuid, + PhaseUuid: phase.Uuid, + Assignee: assignee.OwnerPubKey, + Show: true, + Created: now.Unix(), + OwnerID: "test-owner", + Price: 1000, + Updated: &now, + Paid: false, + } + _, err := db.TestDB.CreateOrEditBounty(recentUnpaidBounty) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(bHandler.GetBountyCards) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/gobounties/bounty-cards?workspace_uuid=%s", workspace.Uuid), nil) + assert.NoError(t, err) + + handler.ServeHTTP(rr, req) + + var response []db.BountyCard + err = json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, rr.Code) + assert.Equal(t, 1, len(response)) + assert.Equal(t, "Recent Unpaid", response[0].Title) + }) + + t.Run("should include recent paid bounty", func(t *testing.T) { + db.TestDB.DeleteAllBounties() + + recentPaidBounty := db.NewBounty{ + ID: 1, + Type: "coding", + Title: "Recent Paid", + Description: "Test Description", + WorkspaceUuid: workspace.Uuid, + PhaseUuid: phase.Uuid, + Assignee: assignee.OwnerPubKey, + Show: true, + Created: now.Unix(), + OwnerID: "test-owner", + Price: 1000, + Updated: &now, + Paid: true, + } + _, err := db.TestDB.CreateOrEditBounty(recentPaidBounty) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(bHandler.GetBountyCards) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/gobounties/bounty-cards?workspace_uuid=%s", workspace.Uuid), nil) + assert.NoError(t, err) + + handler.ServeHTTP(rr, req) + + var response []db.BountyCard + err = json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, rr.Code) + assert.Equal(t, 1, len(response)) + assert.Equal(t, "Recent Paid", response[0].Title) + }) + + t.Run("should exclude old unpaid bounty", func(t *testing.T) { + db.TestDB.DeleteAllBounties() + + oldUnpaidBounty := db.NewBounty{ + ID: 1, + Type: "coding", + Title: "Old Unpaid", + Description: "Test Description", + WorkspaceUuid: workspace.Uuid, + PhaseUuid: phase.Uuid, + Assignee: assignee.OwnerPubKey, + Show: true, + Created: fiveWeeksAgo.Unix(), + OwnerID: "test-owner", + Price: 1000, + Updated: &fiveWeeksAgo, + Paid: false, + } + _, err := db.TestDB.CreateOrEditBounty(oldUnpaidBounty) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(bHandler.GetBountyCards) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/gobounties/bounty-cards?workspace_uuid=%s", workspace.Uuid), nil) + assert.NoError(t, err) + + handler.ServeHTTP(rr, req) + + var response []db.BountyCard + err = json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, rr.Code) + assert.Equal(t, 0, len(response)) + }) + + t.Run("should exclude old paid bounty", func(t *testing.T) { + db.TestDB.DeleteAllBounties() + + oldPaidBounty := db.NewBounty{ + ID: 1, + Type: "coding", + Title: "Old Paid", + Description: "Test Description", + WorkspaceUuid: workspace.Uuid, + PhaseUuid: phase.Uuid, + Assignee: assignee.OwnerPubKey, + Show: true, + Created: threeWeeksAgo.Unix(), + OwnerID: "test-owner", + Price: 1000, + Updated: &threeWeeksAgo, + Paid: true, + } + _, err := db.TestDB.CreateOrEditBounty(oldPaidBounty) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(bHandler.GetBountyCards) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/gobounties/bounty-cards?workspace_uuid=%s", workspace.Uuid), nil) + assert.NoError(t, err) + + handler.ServeHTTP(rr, req) + + var response []db.BountyCard + err = json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err) + assert.Equal(t, http.StatusOK, rr.Code) + assert.Equal(t, 0, len(response)) + }) } From 65a4ee70d5e303e554cfd0de2f48b99d66e48e9a Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Fri, 3 Jan 2025 06:07:45 +0500 Subject: [PATCH 2/2] fix: correct timestamp handling in bounty cards filter --- db/db.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/db.go b/db/db.go index cd934d31a..89773e146 100644 --- a/db/db.go +++ b/db/db.go @@ -1991,8 +1991,8 @@ func (db database) GetWorkspaceBountyCardsData(r *http.Request) []NewBounty { timeFilterQuery = ` AND ( - (NOT paid AND updated > NOW() - INTERVAL '4 weeks') - OR (paid AND updated > NOW() - INTERVAL '2 weeks') + (NOT paid AND EXTRACT(EPOCH FROM updated::timestamp) > EXTRACT(EPOCH FROM (NOW() - INTERVAL '4 weeks'))) + OR (paid AND EXTRACT(EPOCH FROM updated::timestamp) > EXTRACT(EPOCH FROM (NOW() - INTERVAL '2 weeks'))) OR updated IS NULL -- Preserve existing records without updated timestamp )`