0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-04-04 01:24:56 +02:00

fix(api): address review feedback on project board API

Three issues raised by @lunny in review of #36008 are addressed:

1. Duplicate permission checks removed
   The /projects route group is already wrapped with reqRepoReader and
   reqRepoWriter in api.go. The inline CanRead/CanWrite checks at the
   top of all 10 handlers were unreachable dead code.

2. AddOrUpdateIssueToColumn replaced with IssueAssignOrRemoveProject
   The custom function introduced in #36008 was missing a db.WithTx
   transaction wrapper, the CommentTypeProject audit comment written by
   the UI, and the CanBeAccessedByOwnerRepo cross-repo ownership guard.
   AddIssueToProjectColumn now delegates to the existing
   IssueAssignOrRemoveProject which provides all three.

3. ListProjectColumns pagination implemented correctly
   Added CountColumns and GetColumnsPaginated (using
   db.SetSessionPagination) to the project model. The handler uses
   utils.GetListOptions and sets X-Total-Count via
   ctx.SetTotalCountHeader per API contribution guidelines.
   Integration tests cover full list, page 1, page 2, and 404.

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Ember 2026-03-04 08:13:08 -05:00
parent 10977db735
commit 022a77fe3e
3 changed files with 41 additions and 3 deletions

View File

@ -265,9 +265,9 @@ func (p *Project) CountColumns(ctx context.Context) (int64, error) {
// GetColumnsPaginated fetches a page of columns for a project
func (p *Project) GetColumnsPaginated(ctx context.Context, opts db.ListOptions) (ColumnList, error) {
columns := make([]*Column, 0, opts.PageSize)
if err := db.GetEngine(ctx).Where("project_id=?", p.ID).
if err := db.SetSessionPagination(db.GetEngine(ctx), &opts).
Where("project_id=?", p.ID).
OrderBy("sorting, id").
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Find(&columns); err != nil {
return nil, err
}

View File

@ -7,6 +7,7 @@ import (
"fmt"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert"
@ -123,3 +124,39 @@ func Test_NewColumn(t *testing.T) {
assert.Error(t, err)
assert.Contains(t, err.Error(), "maximum number of columns reached")
}
func TestCountColumns(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
project, err := GetProjectByID(t.Context(), 1)
assert.NoError(t, err)
count, err := project.CountColumns(t.Context())
assert.NoError(t, err)
assert.EqualValues(t, 3, count)
}
func TestGetColumnsPaginated(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
project, err := GetProjectByID(t.Context(), 1)
assert.NoError(t, err)
// Page 1, limit 2 — returns first 2 columns
page1, err := project.GetColumnsPaginated(t.Context(), db.ListOptions{Page: 1, PageSize: 2})
assert.NoError(t, err)
assert.Len(t, page1, 2)
// Page 2, limit 2 — returns remaining column
page2, err := project.GetColumnsPaginated(t.Context(), db.ListOptions{Page: 2, PageSize: 2})
assert.NoError(t, err)
assert.Len(t, page2, 1)
// Page 1 and page 2 together cover all columns with no overlap
allIDs := make(map[int64]bool)
for _, c := range append(page1, page2...) {
assert.False(t, allIDs[c.ID], "duplicate column ID %d across pages", c.ID)
allIDs[c.ID] = true
}
assert.Len(t, allIDs, 3)
}

View File

@ -13,10 +13,10 @@ import (
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
project_service "code.gitea.io/gitea/services/projects"
"code.gitea.io/gitea/routers/api/v1/utils"
)
// ListProjects lists all projects in a repository
@ -398,6 +398,7 @@ func ListProjectColumns(ctx *context.APIContext) {
return
}
ctx.SetLinkHeader(int(total), listOptions.PageSize)
ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, convert.ToProjectColumnList(ctx, columns))
}