diff --git a/models/issues/issue.go b/models/issues/issue.go index e5b1bb6ef6fbd..936e59991103e 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1566,6 +1566,26 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { return issues, nil } +// Issues returns a list of issues by given conditions and context. +func IssuesCtx(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) { + sess := db.GetEngine(ctx). + Join("INNER", "repository", "`issue`.repo_id = `repository`.id") + opts.setupSessionWithLimit(sess) + + sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID) + + issues := make([]*Issue, 0, opts.ListOptions.PageSize) + if err := sess.Find(&issues); err != nil { + return nil, fmt.Errorf("unable to query Issues: %w", err) + } + + if err := IssueList(issues).LoadAttributes(); err != nil { + return nil, fmt.Errorf("unable to LoadAttributes for Issues: %w", err) + } + + return issues, nil +} + // CountIssues number return of issues by given conditions. func CountIssues(opts *IssuesOptions) (int64, error) { e := db.GetEngine(db.DefaultContext) diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index bbe2292dd1de0..a9ff8fb4d6af2 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -78,6 +78,46 @@ func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) { return issues.loadRepositories(db.DefaultContext) } +// LoadRepositories loads issues' all repositories in context +func (issues IssueList) LoadRepositoriesCtx(ctx context.Context) ([]*repo_model.Repository, error) { + if len(issues) == 0 { + return nil, nil + } + + repoIDs := issues.getRepoIDs() + repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) + left := len(repoIDs) + for left > 0 { + limit := db.DefaultMaxInSize + if left < limit { + limit = left + } + err := db.GetEngine(ctx). + In("id", repoIDs[:limit]). + Find(&repoMaps) + if err != nil { + return nil, fmt.Errorf("find repository: %w", err) + } + left -= limit + repoIDs = repoIDs[limit:] + } + + for _, issue := range issues { + if issue.Repo == nil { + issue.Repo = repoMaps[issue.RepoID] + } else { + repoMaps[issue.RepoID] = issue.Repo + } + if issue.PullRequest != nil { + issue.PullRequest.BaseRepo = issue.Repo + if issue.PullRequest.HeadRepo == nil { + issue.PullRequest.HeadRepo = repoMaps[issue.PullRequest.HeadRepoID] + } + } + } + return repo_model.ValuesRepository(repoMaps), nil +} + func (issues IssueList) getPosterIDs() []int64 { posterIDs := make(container.Set[int64], len(issues)) for _, issue := range issues { @@ -564,6 +604,11 @@ func (issues IssueList) LoadComments() error { return issues.loadComments(db.DefaultContext, builder.NewCond()) } +// LoadComments loads comments for given context +func (issues IssueList) LoadCommentsCtx(ctx context.Context) error { + return issues.loadComments(ctx, builder.NewCond()) +} + // LoadDiscussComments loads discuss comments func (issues IssueList) LoadDiscussComments() error { return issues.loadComments(db.DefaultContext, builder.Eq{"comment.type": CommentTypeComment}) diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 974781fb53f51..787e94057625e 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -95,6 +95,41 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) { return issueList, nil } +// LoadIssuesFromBoard load issues assigned to this board +func LoadIssuesFromBoardCtx(ctx context.Context, b *project_model.Board) (IssueList, error) { + issueList := make([]*Issue, 0, 10) + + if b.ID != 0 { + issues, err := IssuesCtx(ctx, &IssuesOptions{ + ProjectBoardID: b.ID, + ProjectID: b.ProjectID, + SortType: "project-column-sorting", + }) + if err != nil { + return nil, err + } + issueList = issues + } + + if b.Default { + issues, err := IssuesCtx(ctx, &IssuesOptions{ + ProjectBoardID: -1, // Issues without ProjectBoardID + ProjectID: b.ProjectID, + SortType: "project-column-sorting", + }) + if err != nil { + return nil, err + } + issueList = append(issueList, issues...) + } + + if err := IssueList(issueList).LoadCommentsCtx(ctx); err != nil { + return nil, err + } + + return issueList, nil +} + // LoadIssuesFromBoardList load issues assigned to the boards func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, error) { issuesMap := make(map[int64]IssueList, len(bs)) @@ -108,7 +143,19 @@ func LoadIssuesFromBoardList(bs project_model.BoardList) (map[int64]IssueList, e return issuesMap, nil } -// ChangeProjectAssign changes the project associated with an issue +// LoadIssuesFromBoardList load issues assigned to the boards +func LoadIssuesFromBoardListCtx(ctx context.Context, bs project_model.BoardList) (map[int64]IssueList, error) { + issuesMap := make(map[int64]IssueList, len(bs)) + for i := range bs { + il, err := LoadIssuesFromBoardCtx(ctx, bs[i]) + if err != nil { + return nil, err + } + issuesMap[bs[i].ID] = il + } + return issuesMap, nil +} + func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64) error { ctx, committer, err := db.TxContext() if err != nil { diff --git a/models/project/project.go b/models/project/project.go index 1073d33e0cbef..ddb0577d1e80e 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -106,7 +106,7 @@ func (p *Project) LoadOwner(ctx context.Context) (err error) { if p.Owner != nil { return nil } - p.Owner, err = user_model.GetUserByID(ctx, p.OwnerID) + p.Owner, err = user_model.GetUserByIDCtx(ctx, p.OwnerID) return err } @@ -114,7 +114,7 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) { if p.RepoID == 0 || p.Repo != nil { return nil } - p.Repo, err = repo_model.GetRepositoryByID(ctx, p.RepoID) + p.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, p.RepoID) return err } diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 1ce44d4866d8e..f936592999875 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -198,7 +198,7 @@ func DeleteProject(ctx *context.Context) { return } - if err := project_model.DeleteProjectByID(ctx, p.ID); err != nil { + if err := project_model.DeleteProjectByIDCtx(ctx, p.ID); err != nil { ctx.Flash.Error("DeleteProjectByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.projects.deletion_success")) @@ -302,7 +302,7 @@ func ViewProject(ctx *context.Context) { boards[0].Title = ctx.Tr("repo.projects.type.uncategorized") } - issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards) + issuesMap, err := issues_model.LoadIssuesFromBoardListCtx(ctx, boards) if err != nil { ctx.ServerError("LoadIssuesOfBoards", err) return @@ -319,7 +319,7 @@ func ViewProject(ctx *context.Context) { } if len(referencedIds) > 0 { - if linkedPrs, err := issues_model.Issues(ctx, &issues_model.IssuesOptions{ + if linkedPrs, err := issues_model.IssuesCtx(ctx, &issues_model.IssuesOptions{ IssueIDs: referencedIds, IsPull: util.OptionalBoolTrue, }); err == nil { @@ -647,7 +647,7 @@ func MoveIssues(ctx *context.Context) { return } - if _, err = movedIssues.LoadRepositories(ctx); err != nil { + if _, err = movedIssues.LoadRepositoriesCtx(ctx); err != nil { ctx.ServerError("LoadRepositories", err) return }