0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-17 10:13:37 +02:00
- 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>
This commit is contained in:
silverwind 2026-04-27 12:19:57 +02:00 committed by beardev-in
parent 45832f4d68
commit 438f367ab3
No known key found for this signature in database
GPG Key ID: 625E0CB70AFF32B9
5 changed files with 35 additions and 93 deletions

View File

@ -9,7 +9,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
) )
// CountColumns returns the total number of columns for a project // CountProjectColumns returns the total number of columns for a project
func CountProjectColumns(ctx context.Context, projectID int64) (int64, error) { func CountProjectColumns(ctx context.Context, projectID int64) (int64, error) {
return db.GetEngine(ctx).Where("project_id=?", projectID).Count(&Column{}) return db.GetEngine(ctx).Where("project_id=?", projectID).Count(&Column{})
} }
@ -28,7 +28,7 @@ func GetProjectColumns(ctx context.Context, projectID int64, opts db.ListOptions
} }
func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) { func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) {
columns := make([]*Column, 0, 5) columns := make([]*Column, 0, len(columnsIDs))
if len(columnsIDs) == 0 { if len(columnsIDs) == 0 {
return columns, nil return columns, nil
} }

View File

@ -10,51 +10,36 @@ import (
// Project represents a project // Project represents a project
// swagger:model // swagger:model
type Project struct { type Project struct {
// Unique identifier of the project ID int64 `json:"id"`
ID int64 `json:"id"` Title string `json:"title"`
// Project title
Title string `json:"title"`
// Project description
Description string `json:"description"` Description string `json:"description"`
// Owner ID (for organization or user projects) OwnerID int64 `json:"owner_id,omitempty"`
OwnerID int64 `json:"owner_id,omitempty"` RepoID int64 `json:"repo_id,omitempty"`
// Repository ID (for repository projects) CreatorID int64 `json:"creator_id"`
RepoID int64 `json:"repo_id,omitempty"` IsClosed bool `json:"is_closed"`
// Creator ID
CreatorID int64 `json:"creator_id"`
// Whether the project is closed
IsClosed bool `json:"is_closed"`
// Template type: 0=none, 1=basic_kanban, 2=bug_triage // Template type: 0=none, 1=basic_kanban, 2=bug_triage
TemplateType int `json:"template_type"` TemplateType int `json:"template_type"`
// Card type: 0=text_only, 1=images_and_text // Card type: 0=text_only, 1=images_and_text
CardType int `json:"card_type"` CardType int `json:"card_type"`
// Project type: 1=individual, 2=repository, 3=organization // Project type: 1=individual, 2=repository, 3=organization
Type int `json:"type"` Type int `json:"type"`
// Number of open issues NumOpenIssues int64 `json:"num_open_issues,omitempty"`
NumOpenIssues int64 `json:"num_open_issues,omitempty"`
// Number of closed issues
NumClosedIssues int64 `json:"num_closed_issues,omitempty"` NumClosedIssues int64 `json:"num_closed_issues,omitempty"`
// Total number of issues NumIssues int64 `json:"num_issues,omitempty"`
NumIssues int64 `json:"num_issues,omitempty"`
// Created time
// swagger:strfmt date-time // swagger:strfmt date-time
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Updated time
// swagger:strfmt date-time // swagger:strfmt date-time
Updated time.Time `json:"updated"` Updated time.Time `json:"updated"`
// Closed time
// swagger:strfmt date-time // swagger:strfmt date-time
ClosedDate *time.Time `json:"closed_date,omitempty"` ClosedDate *time.Time `json:"closed_date,omitempty"`
// Project URL URL string `json:"url,omitempty"`
URL string `json:"url,omitempty"`
} }
// CreateProjectOption represents options for creating a project // CreateProjectOption represents options for creating a project
// swagger:model // swagger:model
type CreateProjectOption struct { type CreateProjectOption struct {
// required: true // required: true
Title string `json:"title" binding:"Required"` Title string `json:"title" binding:"Required"`
// Project description
Description string `json:"description"` Description string `json:"description"`
// Template type: 0=none, 1=basic_kanban, 2=bug_triage // Template type: 0=none, 1=basic_kanban, 2=bug_triage
TemplateType int `json:"template_type"` TemplateType int `json:"template_type"`
@ -65,9 +50,7 @@ type CreateProjectOption struct {
// EditProjectOption represents options for editing a project // EditProjectOption represents options for editing a project
// swagger:model // swagger:model
type EditProjectOption struct { type EditProjectOption struct {
// Project title Title *string `json:"title,omitempty"`
Title *string `json:"title,omitempty"`
// Project description
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
// Card type: 0=text_only, 1=images_and_text // Card type: 0=text_only, 1=images_and_text
CardType *int `json:"card_type,omitempty"` CardType *int `json:"card_type,omitempty"`
@ -78,26 +61,16 @@ type EditProjectOption struct {
// ProjectColumn represents a project column (board) // ProjectColumn represents a project column (board)
// swagger:model // swagger:model
type ProjectColumn struct { type ProjectColumn struct {
// Unique identifier of the column ID int64 `json:"id"`
ID int64 `json:"id"` Title string `json:"title"`
// Column title Default bool `json:"default"`
Title string `json:"title"` Sorting int `json:"sorting"`
// Whether this is the default column Color string `json:"color,omitempty"`
Default bool `json:"default"` ProjectID int64 `json:"project_id"`
// Sorting order CreatorID int64 `json:"creator_id"`
Sorting int `json:"sorting"` NumIssues int64 `json:"num_issues,omitempty"`
// Column color (hex format)
Color string `json:"color,omitempty"`
// Project ID
ProjectID int64 `json:"project_id"`
// Creator ID
CreatorID int64 `json:"creator_id"`
// Number of issues in this column
NumIssues int64 `json:"num_issues,omitempty"`
// Created time
// swagger:strfmt date-time // swagger:strfmt date-time
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Updated time
// swagger:strfmt date-time // swagger:strfmt date-time
Updated time.Time `json:"updated"` Updated time.Time `json:"updated"`
} }
@ -107,17 +80,15 @@ type ProjectColumn struct {
type CreateProjectColumnOption struct { type CreateProjectColumnOption struct {
// required: true // required: true
Title string `json:"title" binding:"Required"` Title string `json:"title" binding:"Required"`
// Column color (hex format, e.g., #FF0000) // Column color (hex format, e.g. #FF0000)
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
} }
// EditProjectColumnOption represents options for editing a project column // EditProjectColumnOption represents options for editing a project column
// swagger:model // swagger:model
type EditProjectColumnOption struct { type EditProjectColumnOption struct {
// Column title
Title *string `json:"title,omitempty"` Title *string `json:"title,omitempty"`
// Column color (hex format) // Column color (hex format)
Color *string `json:"color,omitempty"` Color *string `json:"color,omitempty"`
// Sorting order Sorting *int `json:"sorting,omitempty"`
Sorting *int `json:"sorting,omitempty"`
} }

View File

@ -118,6 +118,9 @@ func ListProjects(ctx *context.APIContext) {
return return
} }
for _, p := range projects {
p.Repo = ctx.Repo.Repository
}
apiProjects := convert.ToProjectList(ctx, projects) apiProjects := convert.ToProjectList(ctx, projects)
ctx.SetLinkHeader(count, listOptions.PageSize) ctx.SetLinkHeader(count, listOptions.PageSize)
@ -217,6 +220,7 @@ func CreateProject(ctx *context.APIContext) {
return return
} }
p.Repo = ctx.Repo.Repository
ctx.JSON(http.StatusCreated, convert.ToProject(ctx, p)) ctx.JSON(http.StatusCreated, convert.ToProject(ctx, p))
} }

View File

@ -35,15 +35,11 @@ func ToProject(ctx context.Context, p *project_model.Project) *api.Project {
project.ClosedDate = &t project.ClosedDate = &t
} }
// Generate project URL // Repo/Owner are expected to be preloaded by the caller to avoid N+1 lookups.
if p.Type == project_model.TypeRepository && p.RepoID > 0 { if p.Type == project_model.TypeRepository && p.Repo != nil {
if err := p.LoadRepo(ctx); err == nil && p.Repo != nil { project.URL = project_model.ProjectLinkForRepo(p.Repo, p.ID)
project.URL = project_model.ProjectLinkForRepo(p.Repo, p.ID) } else if p.Owner != nil {
} project.URL = project_model.ProjectLinkForOrg(p.Owner, p.ID)
} else if p.OwnerID > 0 {
if err := p.LoadOwner(ctx); err == nil && p.Owner != nil {
project.URL = project_model.ProjectLinkForOrg(p.Owner, p.ID)
}
} }
return project return project

View File

@ -24160,7 +24160,7 @@
], ],
"properties": { "properties": {
"color": { "color": {
"description": "Column color (hex format, e.g., #FF0000)", "description": "Column color (hex format, e.g. #FF0000)",
"type": "string", "type": "string",
"x-go-name": "Color" "x-go-name": "Color"
}, },
@ -24185,7 +24185,6 @@
"x-go-name": "CardType" "x-go-name": "CardType"
}, },
"description": { "description": {
"description": "Project description",
"type": "string", "type": "string",
"x-go-name": "Description" "x-go-name": "Description"
}, },
@ -25332,13 +25331,11 @@
"x-go-name": "Color" "x-go-name": "Color"
}, },
"sorting": { "sorting": {
"description": "Sorting order",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "Sorting" "x-go-name": "Sorting"
}, },
"title": { "title": {
"description": "Column title",
"type": "string", "type": "string",
"x-go-name": "Title" "x-go-name": "Title"
} }
@ -25356,7 +25353,6 @@
"x-go-name": "CardType" "x-go-name": "CardType"
}, },
"description": { "description": {
"description": "Project description",
"type": "string", "type": "string",
"x-go-name": "Description" "x-go-name": "Description"
}, },
@ -25366,7 +25362,6 @@
"x-go-name": "State" "x-go-name": "State"
}, },
"title": { "title": {
"description": "Project title",
"type": "string", "type": "string",
"x-go-name": "Title" "x-go-name": "Title"
} }
@ -28081,65 +28076,54 @@
"x-go-name": "CardType" "x-go-name": "CardType"
}, },
"closed_date": { "closed_date": {
"description": "Closed time",
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"x-go-name": "ClosedDate" "x-go-name": "ClosedDate"
}, },
"created": { "created": {
"description": "Created time",
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"x-go-name": "Created" "x-go-name": "Created"
}, },
"creator_id": { "creator_id": {
"description": "Creator ID",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "CreatorID" "x-go-name": "CreatorID"
}, },
"description": { "description": {
"description": "Project description",
"type": "string", "type": "string",
"x-go-name": "Description" "x-go-name": "Description"
}, },
"id": { "id": {
"description": "Unique identifier of the project",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "ID" "x-go-name": "ID"
}, },
"is_closed": { "is_closed": {
"description": "Whether the project is closed",
"type": "boolean", "type": "boolean",
"x-go-name": "IsClosed" "x-go-name": "IsClosed"
}, },
"num_closed_issues": { "num_closed_issues": {
"description": "Number of closed issues",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "NumClosedIssues" "x-go-name": "NumClosedIssues"
}, },
"num_issues": { "num_issues": {
"description": "Total number of issues",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "NumIssues" "x-go-name": "NumIssues"
}, },
"num_open_issues": { "num_open_issues": {
"description": "Number of open issues",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "NumOpenIssues" "x-go-name": "NumOpenIssues"
}, },
"owner_id": { "owner_id": {
"description": "Owner ID (for organization or user projects)",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "OwnerID" "x-go-name": "OwnerID"
}, },
"repo_id": { "repo_id": {
"description": "Repository ID (for repository projects)",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "RepoID" "x-go-name": "RepoID"
@ -28151,7 +28135,6 @@
"x-go-name": "TemplateType" "x-go-name": "TemplateType"
}, },
"title": { "title": {
"description": "Project title",
"type": "string", "type": "string",
"x-go-name": "Title" "x-go-name": "Title"
}, },
@ -28162,13 +28145,11 @@
"x-go-name": "Type" "x-go-name": "Type"
}, },
"updated": { "updated": {
"description": "Updated time",
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"x-go-name": "Updated" "x-go-name": "Updated"
}, },
"url": { "url": {
"description": "Project URL",
"type": "string", "type": "string",
"x-go-name": "URL" "x-go-name": "URL"
} }
@ -28180,58 +28161,48 @@
"type": "object", "type": "object",
"properties": { "properties": {
"color": { "color": {
"description": "Column color (hex format)",
"type": "string", "type": "string",
"x-go-name": "Color" "x-go-name": "Color"
}, },
"created": { "created": {
"description": "Created time",
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"x-go-name": "Created" "x-go-name": "Created"
}, },
"creator_id": { "creator_id": {
"description": "Creator ID",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "CreatorID" "x-go-name": "CreatorID"
}, },
"default": { "default": {
"description": "Whether this is the default column",
"type": "boolean", "type": "boolean",
"x-go-name": "Default" "x-go-name": "Default"
}, },
"id": { "id": {
"description": "Unique identifier of the column",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "ID" "x-go-name": "ID"
}, },
"num_issues": { "num_issues": {
"description": "Number of issues in this column",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "NumIssues" "x-go-name": "NumIssues"
}, },
"project_id": { "project_id": {
"description": "Project ID",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "ProjectID" "x-go-name": "ProjectID"
}, },
"sorting": { "sorting": {
"description": "Sorting order",
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"x-go-name": "Sorting" "x-go-name": "Sorting"
}, },
"title": { "title": {
"description": "Column title",
"type": "string", "type": "string",
"x-go-name": "Title" "x-go-name": "Title"
}, },
"updated": { "updated": {
"description": "Updated time",
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
"x-go-name": "Updated" "x-go-name": "Updated"