Per review feedback, the 127-column cap is intentional (maxProjectColumns
is 20), so the DB schema is left as-is and no migration is needed. Reverts
the Column.Sorting widening to match.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- Rename response timestamps to created_at / updated_at / closed_at
- Replace is_closed bool with state ("open" / "closed") via api.StateType
- Switch template_type / card_type / type to string enums with input validation
- Embed creator User object on Project and ProjectColumn (batched lookup)
- Add absolute html_url; drop relative url
- Add POST /repos/.../projects/{id}/issues/{issue_id}/move with optional sorting
- Validate column hex color and reject writes to closed projects
- Document issue-only project scope in swagger
- Push project-issue existence check into project_model.IsIssueInColumn
- Add project_service.ErrIssueNotInProject sentinel for the move endpoint
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- EditProject: wrap field updates and ChangeProjectStatus in db.WithTx so
a status-change failure doesn't leave a partially applied PATCH.
- Validate EditProjectOption.State against open/closed; 422 on other
values instead of silently treating them as open.
- Align missing-issue status to 404 (the URL targets a missing resource);
update existing test that was asserting the old 422.
- RemoveIssueFromProjectColumn: verify the project_issue row matches the
URL column before clearing the issue's project assignment, since
IssueAssignOrRemoveProject(projectID=0) detaches the issue from any
project regardless of column. Returns 404 if the issue isn't in this
column. New test covers the cross-column case.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- Drop lazy LoadRepo/LoadOwner in convert.ToProject; rely on caller
preloading. ListProjects sets Repo from ctx.Repo.Repository on each
project; CreateProject does the same on the new project. Avoids
N+1 queries for repo-scoped list endpoints.
- Strip redundant API struct field comments that just restate the
field name; keep the ones that document enum values.
- Pre-allocate GetColumnsByIDs result slice with len(columnsIDs).
- Fix CountProjectColumns doc comment (was "CountColumns").
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- Use ParseIssueFilterStateIsClosed for ListProjects state parsing
- Add SortTypeProjectColumnSorting const, replace magic string
- Use GetIssueByRepoID and dedupe Add/Remove issue handlers
- Migrate Column.Sorting from int8 to int (drops 127-column limit, allows
the API to expose a normal int without truncation)
- Introduce project_service.UpdateProject with optional.Option fields,
use it from the API EditProject handler
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- Replace separate POST /close and /reopen endpoints with a state field
on EditProjectOption, matching the milestone and issue API patterns
- Extract getRepoProjectByID and getRepoProjectColumn helpers to
deduplicate repeated lookup-and-error-handle patterns
- Use LoadIssueNumbersForProject (singular) for single-project handlers
- Remove unnecessary LoadIssueNumbersForProjects call on CreateProject
since a new project always has zero issues
- Remove unnecessary WHAT comments
- Fix copyright year in routers/api/v1/repo/project.go
Co-Authored-By: Claude (claude-opus-4-6) <noreply@anthropic.com>
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 adds a complete REST API implementation for managing repository
project boards, including projects, columns, and adding issues to columns.
API Endpoints:
- GET /repos/{owner}/{repo}/projects - List projects
- POST /repos/{owner}/{repo}/projects - Create project
- GET /repos/{owner}/{repo}/projects/{id} - Get project
- PATCH /repos/{owner}/{repo}/projects/{id} - Update project
- DELETE /repos/{owner}/{repo}/projects/{id} - Delete project
- GET /repos/{owner}/{repo}/projects/{id}/columns - List columns
- POST /repos/{owner}/{repo}/projects/{id}/columns - Create column
- PATCH /repos/{owner}/{repo}/projects/columns/{id} - Update column
- DELETE /repos/{owner}/{repo}/projects/columns/{id} - Delete column
- POST /repos/{owner}/{repo}/projects/columns/{id}/issues - Add issue
Features:
- Full Swagger/OpenAPI documentation
- Proper permission checks
- Pagination support for list endpoints
- State filtering (open/closed/all)
- Comprehensive error handling
- Token-based authentication with scope validation
- Archive repository protection
New Files:
- modules/structs/project.go: API data structures
- routers/api/v1/repo/project.go: API handlers
- routers/api/v1/swagger/project.go: Swagger responses
- services/convert/project.go: Model converters
- tests/integration/api_repo_project_test.go: Integration tests
Modified Files:
- models/project/issue.go: Added AddOrUpdateIssueToColumn function
- routers/api/v1/api.go: Registered project API routes
- routers/api/v1/swagger/options.go: Added project option types
- templates/swagger/v1_json.tmpl: Regenerated swagger spec
fix(api): remove duplicated permission checks in project handlers
Route middleware reqRepoReader(unit.TypeProjects) wraps the entire
/projects route group, and reqRepoWriter(unit.TypeProjects) is applied
to each mutating route individually in api.go. These middleware run
before any handler fires and already gate access correctly.
The inline CanRead/CanWrite checks at the top of all 10 handlers were
therefore unreachable dead code — removed from ListProjects, GetProject,
CreateProject, EditProject, DeleteProject, ListProjectColumns,
CreateProjectColumn, EditProjectColumn, DeleteProjectColumn, and
AddIssueToProjectColumn.
The now-unused "code.gitea.io/gitea/models/unit" import is also removed.
Addresses review feedback on: https://github.com/go-gitea/gitea/pull/36008
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
fix(api): replace AddOrUpdateIssueToColumn with IssueAssignOrRemoveProject
The custom AddOrUpdateIssueToColumn function introduced by this PR was
missing three things that the existing IssueAssignOrRemoveProject provides:
1. db.WithTx transaction wrapper — raw DB updates without a transaction
can leave the database in a partial state on error.
2. CreateComment(CommentTypeProject) — assigning an issue to a project
column via the UI creates a comment on the issue timeline. The API
doing the same action silently was an inconsistency.
3. CanBeAccessedByOwnerRepo ownership check — IssueAssignOrRemoveProject
validates that the issue is accessible within the repo/org context
before mutating state.
AddOrUpdateIssueToColumn is removed entirely. AddIssueToProjectColumn
now delegates to issues_model.IssueAssignOrRemoveProject, which already
has the issue object loaded earlier in the handler.
Addresses review feedback on: https://github.com/go-gitea/gitea/pull/36008
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
fix(api): remove unnecessary pagination from ListProjectColumns
Project columns are few in number by design (typically 3-8 per board).
The previous implementation fetched all columns from the DB then sliced
the result in memory — adding complexity and a misleading Link header
without any practical benefit.
ListProjectColumns now returns all columns directly. The page/limit
query parameters and associated swagger docs are removed.
Addresses review feedback on: https://github.com/go-gitea/gitea/pull/36008
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
fix(api): regenerate swagger spec after removing ListProjectColumns pagination
Removes the page and limit parameters from the generated swagger spec
for the ListProjectColumns endpoint, matching the handler change that
dropped in-memory pagination.
Co-authored-by: Claude <noreply@anthropic.com>
test(api): remove pagination assertion from TestAPIListProjectColumns
ListProjectColumns no longer supports pagination — it returns all columns
directly. Remove the page/limit test case that expected 2 of 3 columns.
Co-authored-by: Claude <noreply@anthropic.com>
fix(api): implement proper pagination for ListProjectColumns
Per contribution guidelines, list endpoints must support page/limit
query params and set X-Total-Count header.
- Add CountColumns and GetColumnsPaginated to project model (DB-level,
not in-memory slicing)
- ListProjectColumns uses utils.GetListOptions, calls paginated model
functions, and sets X-Total-Count via ctx.SetTotalCountHeader
- Restore page/limit swagger doc params on the endpoint
- Regenerate swagger spec
- Integration test covers: full list with X-Total-Count, page 1 of 2,
page 2 of 2, and 404 for non-existent project
Co-authored-by: Claude <noreply@anthropic.com>