diff options
Diffstat (limited to 'models/issue.go')
-rw-r--r-- | models/issue.go | 301 |
1 files changed, 156 insertions, 145 deletions
diff --git a/models/issue.go b/models/issue.go index 9e63ac4e58..a1f5373583 100644 --- a/models/issue.go +++ b/models/issue.go @@ -12,6 +12,7 @@ import ( "strconv" "strings" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/references" @@ -82,12 +83,18 @@ const ( issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[xX]\]\s.)|(\n\s*[-*]\s\[[xX]\]\s.)` ) +// IssueIndex represents the issue index table +type IssueIndex db.ResourceIndex + func init() { issueTasksPat = regexp.MustCompile(issueTasksRegexpStr) issueTasksDonePat = regexp.MustCompile(issueTasksDoneRegexpStr) + + db.RegisterModel(new(Issue)) + db.RegisterModel(new(IssueIndex)) } -func (issue *Issue) loadTotalTimes(e Engine) (err error) { +func (issue *Issue) loadTotalTimes(e db.Engine) (err error) { opts := FindTrackedTimesOptions{IssueID: issue.ID} issue.TotalTrackedTime, err = opts.toSession(e).SumInt(&TrackedTime{}, "time") if err != nil { @@ -106,10 +113,10 @@ func (issue *Issue) IsOverdue() bool { // LoadRepo loads issue's repository func (issue *Issue) LoadRepo() error { - return issue.loadRepo(x) + return issue.loadRepo(db.DefaultContext().Engine()) } -func (issue *Issue) loadRepo(e Engine) (err error) { +func (issue *Issue) loadRepo(e db.Engine) (err error) { if issue.Repo == nil { issue.Repo, err = getRepositoryByID(e, issue.RepoID) if err != nil { @@ -121,10 +128,10 @@ func (issue *Issue) loadRepo(e Engine) (err error) { // IsTimetrackerEnabled returns true if the repo enables timetracking func (issue *Issue) IsTimetrackerEnabled() bool { - return issue.isTimetrackerEnabled(x) + return issue.isTimetrackerEnabled(db.DefaultContext().Engine()) } -func (issue *Issue) isTimetrackerEnabled(e Engine) bool { +func (issue *Issue) isTimetrackerEnabled(e db.Engine) bool { if err := issue.loadRepo(e); err != nil { log.Error(fmt.Sprintf("loadRepo: %v", err)) return false @@ -138,7 +145,7 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { return nil, fmt.Errorf("Issue is not a pull request") } - pr, err = getPullRequestByIssueID(x, issue.ID) + pr, err = getPullRequestByIssueID(db.DefaultContext().Engine(), issue.ID) if err != nil { return nil, err } @@ -148,10 +155,10 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { // LoadLabels loads labels func (issue *Issue) LoadLabels() error { - return issue.loadLabels(x) + return issue.loadLabels(db.DefaultContext().Engine()) } -func (issue *Issue) loadLabels(e Engine) (err error) { +func (issue *Issue) loadLabels(e db.Engine) (err error) { if issue.Labels == nil { issue.Labels, err = getLabelsByIssueID(e, issue.ID) if err != nil { @@ -163,10 +170,10 @@ func (issue *Issue) loadLabels(e Engine) (err error) { // LoadPoster loads poster func (issue *Issue) LoadPoster() error { - return issue.loadPoster(x) + return issue.loadPoster(db.DefaultContext().Engine()) } -func (issue *Issue) loadPoster(e Engine) (err error) { +func (issue *Issue) loadPoster(e db.Engine) (err error) { if issue.Poster == nil { issue.Poster, err = getUserByID(e, issue.PosterID) if err != nil { @@ -182,7 +189,7 @@ func (issue *Issue) loadPoster(e Engine) (err error) { return } -func (issue *Issue) loadPullRequest(e Engine) (err error) { +func (issue *Issue) loadPullRequest(e db.Engine) (err error) { if issue.IsPull && issue.PullRequest == nil { issue.PullRequest, err = getPullRequestByIssueID(e, issue.ID) if err != nil { @@ -198,19 +205,19 @@ func (issue *Issue) loadPullRequest(e Engine) (err error) { // LoadPullRequest loads pull request info func (issue *Issue) LoadPullRequest() error { - return issue.loadPullRequest(x) + return issue.loadPullRequest(db.DefaultContext().Engine()) } -func (issue *Issue) loadComments(e Engine) (err error) { +func (issue *Issue) loadComments(e db.Engine) (err error) { return issue.loadCommentsByType(e, CommentTypeUnknown) } // LoadDiscussComments loads discuss comments func (issue *Issue) LoadDiscussComments() error { - return issue.loadCommentsByType(x, CommentTypeComment) + return issue.loadCommentsByType(db.DefaultContext().Engine(), CommentTypeComment) } -func (issue *Issue) loadCommentsByType(e Engine, tp CommentType) (err error) { +func (issue *Issue) loadCommentsByType(e db.Engine, tp CommentType) (err error) { if issue.Comments != nil { return nil } @@ -221,7 +228,7 @@ func (issue *Issue) loadCommentsByType(e Engine, tp CommentType) (err error) { return err } -func (issue *Issue) loadReactions(e Engine) (err error) { +func (issue *Issue) loadReactions(e db.Engine) (err error) { if issue.Reactions != nil { return nil } @@ -255,7 +262,7 @@ func (issue *Issue) loadReactions(e Engine) (err error) { return nil } -func (issue *Issue) loadMilestone(e Engine) (err error) { +func (issue *Issue) loadMilestone(e db.Engine) (err error) { if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 { issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) if err != nil && !IsErrMilestoneNotExist(err) { @@ -265,7 +272,7 @@ func (issue *Issue) loadMilestone(e Engine) (err error) { return nil } -func (issue *Issue) loadAttributes(e Engine) (err error) { +func (issue *Issue) loadAttributes(e db.Engine) (err error) { if err = issue.loadRepo(e); err != nil { return } @@ -320,18 +327,18 @@ func (issue *Issue) loadAttributes(e Engine) (err error) { // LoadAttributes loads the attribute of this issue. func (issue *Issue) LoadAttributes() error { - return issue.loadAttributes(x) + return issue.loadAttributes(db.DefaultContext().Engine()) } // LoadMilestone load milestone of this issue. func (issue *Issue) LoadMilestone() error { - return issue.loadMilestone(x) + return issue.loadMilestone(db.DefaultContext().Engine()) } // GetIsRead load the `IsRead` field of the issue func (issue *Issue) GetIsRead(userID int64) error { issueUser := &IssueUser{IssueID: issue.ID, UID: userID} - if has, err := x.Get(issueUser); err != nil { + if has, err := db.DefaultContext().Engine().Get(issueUser); err != nil { return err } else if !has { issue.IsRead = false @@ -398,13 +405,13 @@ func (issue *Issue) IsPoster(uid int64) bool { return issue.OriginalAuthorID == 0 && issue.PosterID == uid } -func (issue *Issue) hasLabel(e Engine, labelID int64) bool { +func (issue *Issue) hasLabel(e db.Engine, labelID int64) bool { return hasIssueLabel(e, issue.ID, labelID) } // HasLabel returns true if issue has been labeled by given ID. func (issue *Issue) HasLabel(labelID int64) bool { - return issue.hasLabel(x, labelID) + return issue.hasLabel(db.DefaultContext().Engine(), labelID) } // ReplyReference returns tokenized address to use for email reply headers @@ -419,15 +426,15 @@ func (issue *Issue) ReplyReference() string { return fmt.Sprintf("%s/%s/%d@%s", issue.Repo.FullName(), path, issue.Index, setting.Domain) } -func (issue *Issue) addLabel(e *xorm.Session, label *Label, doer *User) error { +func (issue *Issue) addLabel(e db.Engine, label *Label, doer *User) error { return newIssueLabel(e, issue, label, doer) } -func (issue *Issue) addLabels(e *xorm.Session, labels []*Label, doer *User) error { +func (issue *Issue) addLabels(e db.Engine, labels []*Label, doer *User) error { return newIssueLabels(e, issue, labels, doer) } -func (issue *Issue) getLabels(e Engine) (err error) { +func (issue *Issue) getLabels(e db.Engine) (err error) { if len(issue.Labels) > 0 { return nil } @@ -439,11 +446,11 @@ func (issue *Issue) getLabels(e Engine) (err error) { return nil } -func (issue *Issue) removeLabel(e *xorm.Session, doer *User, label *Label) error { +func (issue *Issue) removeLabel(e db.Engine, doer *User, label *Label) error { return deleteIssueLabel(e, issue, label, doer) } -func (issue *Issue) clearLabels(e *xorm.Session, doer *User) (err error) { +func (issue *Issue) clearLabels(e db.Engine, doer *User) (err error) { if err = issue.getLabels(e); err != nil { return fmt.Errorf("getLabels: %v", err) } @@ -460,19 +467,19 @@ func (issue *Issue) clearLabels(e *xorm.Session, doer *User) (err error) { // ClearLabels removes all issue labels as the given user. // Triggers appropriate WebHooks, if any. func (issue *Issue) ClearLabels(doer *User) (err error) { - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err := issue.loadRepo(sess); err != nil { + if err := issue.loadRepo(ctx.Engine()); err != nil { return err - } else if err = issue.loadPullRequest(sess); err != nil { + } else if err = issue.loadPullRequest(ctx.Engine()); err != nil { return err } - perm, err := getUserRepoPermission(sess, issue.Repo, doer) + perm, err := getUserRepoPermission(ctx.Engine(), issue.Repo, doer) if err != nil { return err } @@ -480,11 +487,11 @@ func (issue *Issue) ClearLabels(doer *User) (err error) { return ErrRepoLabelNotExist{} } - if err = issue.clearLabels(sess, doer); err != nil { + if err = issue.clearLabels(ctx.Engine(), doer); err != nil { return err } - if err = sess.Commit(); err != nil { + if err = committer.Commit(); err != nil { return fmt.Errorf("Commit: %v", err) } @@ -508,17 +515,17 @@ func (ts labelSorter) Swap(i, j int) { // ReplaceLabels removes all current labels and add new labels to the issue. // Triggers appropriate WebHooks, if any. func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) { - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err = issue.loadRepo(sess); err != nil { + if err = issue.loadRepo(ctx.Engine()); err != nil { return err } - if err = issue.loadLabels(sess); err != nil { + if err = issue.loadLabels(ctx.Engine()); err != nil { return err } @@ -554,23 +561,23 @@ func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) { toRemove = append(toRemove, issue.Labels[removeIndex:]...) if len(toAdd) > 0 { - if err = issue.addLabels(sess, toAdd, doer); err != nil { + if err = issue.addLabels(ctx.Engine(), toAdd, doer); err != nil { return fmt.Errorf("addLabels: %v", err) } } for _, l := range toRemove { - if err = issue.removeLabel(sess, doer, l); err != nil { + if err = issue.removeLabel(ctx.Engine(), doer, l); err != nil { return fmt.Errorf("removeLabel: %v", err) } } issue.Labels = nil - if err = issue.loadLabels(sess); err != nil { + if err = issue.loadLabels(ctx.Engine()); err != nil { return err } - return sess.Commit() + return committer.Commit() } // ReadBy sets issue to be read by given user. @@ -579,17 +586,17 @@ func (issue *Issue) ReadBy(userID int64) error { return err } - return setIssueNotificationStatusReadIfUnread(x, userID, issue.ID) + return setIssueNotificationStatusReadIfUnread(db.DefaultContext().Engine(), userID, issue.ID) } -func updateIssueCols(e Engine, issue *Issue, cols ...string) error { +func updateIssueCols(e db.Engine, issue *Issue, cols ...string) error { if _, err := e.ID(issue.ID).Cols(cols...).Update(issue); err != nil { return err } return nil } -func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed, isMergePull bool) (*Comment, error) { +func (issue *Issue) changeStatus(e db.Engine, doer *User, isClosed, isMergePull bool) (*Comment, error) { // Reload the issue currentIssue, err := getIssueByID(e, issue.ID) if err != nil { @@ -612,7 +619,7 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed, isMergeP return issue.doChangeStatus(e, doer, isMergePull) } -func (issue *Issue) doChangeStatus(e *xorm.Session, doer *User, isMergePull bool) (*Comment, error) { +func (issue *Issue) doChangeStatus(e db.Engine, doer *User, isMergePull bool) (*Comment, error) { // Check for open dependencies if issue.IsClosed && issue.Repo.isDependenciesEnabled(e) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies @@ -675,25 +682,25 @@ func (issue *Issue) doChangeStatus(e *xorm.Session, doer *User, isMergePull bool // ChangeStatus changes issue status to open or closed. func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (*Comment, error) { - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return nil, err } + defer committer.Close() - if err := issue.loadRepo(sess); err != nil { + if err := issue.loadRepo(ctx.Engine()); err != nil { return nil, err } - if err := issue.loadPoster(sess); err != nil { + if err := issue.loadPoster(ctx.Engine()); err != nil { return nil, err } - comment, err := issue.changeStatus(sess, doer, isClosed, false) + comment, err := issue.changeStatus(ctx.Engine(), doer, isClosed, false) if err != nil { return nil, err } - if err = sess.Commit(); err != nil { + if err = committer.Commit(); err != nil { return nil, fmt.Errorf("Commit: %v", err) } @@ -702,18 +709,17 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (*Comment, error) { // ChangeTitle changes the title of this issue, as the given user. func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) { - sess := x.NewSession() - defer sess.Close() - - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err = updateIssueCols(sess, issue, "name"); err != nil { + if err = updateIssueCols(ctx.Engine(), issue, "name"); err != nil { return fmt.Errorf("updateIssueCols: %v", err) } - if err = issue.loadRepo(sess); err != nil { + if err = issue.loadRepo(ctx.Engine()); err != nil { return fmt.Errorf("loadRepo: %v", err) } @@ -725,43 +731,42 @@ func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) { OldTitle: oldTitle, NewTitle: issue.Title, } - if _, err = createComment(sess, opts); err != nil { + if _, err = createComment(ctx.Engine(), opts); err != nil { return fmt.Errorf("createComment: %v", err) } - if err = issue.addCrossReferences(sess, doer, true); err != nil { + if err = issue.addCrossReferences(ctx.Engine(), doer, true); err != nil { return err } - return sess.Commit() + return committer.Commit() } // ChangeRef changes the branch of this issue, as the given user. func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) { - sess := x.NewSession() - defer sess.Close() - - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err = updateIssueCols(sess, issue, "ref"); err != nil { + if err = updateIssueCols(ctx.Engine(), issue, "ref"); err != nil { return fmt.Errorf("updateIssueCols: %v", err) } - return sess.Commit() + return committer.Commit() } // AddDeletePRBranchComment adds delete branch comment for pull request issue func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branchName string) error { - issue, err := getIssueByID(x, issueID) + issue, err := getIssueByID(db.DefaultContext().Engine(), issueID) if err != nil { return err } - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() opts := &CreateCommentOptions{ Type: CommentTypeDeleteBranch, Doer: doer, @@ -769,52 +774,52 @@ func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branc Issue: issue, OldRef: branchName, } - if _, err = createComment(sess, opts); err != nil { + if _, err = createComment(ctx.Engine(), opts); err != nil { return err } - return sess.Commit() + return committer.Commit() } // UpdateAttachments update attachments by UUIDs for the issue func (issue *Issue) UpdateAttachments(uuids []string) (err error) { - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } - attachments, err := getAttachmentsByUUIDs(sess, uuids) + defer committer.Close() + attachments, err := getAttachmentsByUUIDs(ctx.Engine(), uuids) if err != nil { return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", uuids, err) } for i := 0; i < len(attachments); i++ { attachments[i].IssueID = issue.ID - if err := updateAttachment(sess, attachments[i]); err != nil { + if err := updateAttachment(ctx.Engine(), attachments[i]); err != nil { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } - return sess.Commit() + return committer.Commit() } // ChangeContent changes issue content, as the given user. func (issue *Issue) ChangeContent(doer *User, content string) (err error) { issue.Content = content - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err = updateIssueCols(sess, issue, "content"); err != nil { + if err = updateIssueCols(ctx.Engine(), issue, "content"); err != nil { return fmt.Errorf("UpdateIssueCols: %v", err) } - if err = issue.addCrossReferences(sess, doer, true); err != nil { + if err = issue.addCrossReferences(ctx.Engine(), doer, true); err != nil { return err } - return sess.Commit() + return committer.Commit() } // GetTasks returns the amount of tasks in the issues content @@ -849,7 +854,7 @@ func (issue *Issue) GetLastEventLabel() string { // GetLastComment return last comment for the current issue. func (issue *Issue) GetLastComment() (*Comment, error) { var c Comment - exist, err := x.Where("type = ?", CommentTypeComment). + exist, err := db.DefaultContext().Engine().Where("type = ?", CommentTypeComment). And("issue_id = ?", issue.ID).Desc("id").Get(&c) if err != nil { return nil, err @@ -880,7 +885,7 @@ type NewIssueOptions struct { IsPull bool } -func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { +func newIssue(e db.Engine, doer *User, opts NewIssueOptions) (err error) { opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) if opts.Issue.MilestoneID > 0 { @@ -985,44 +990,44 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { // RecalculateIssueIndexForRepo create issue_index for repo if not exist and // update it based on highest index of existing issues assigned to a repo func RecalculateIssueIndexForRepo(repoID int64) error { - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err := upsertResourceIndex(sess, "issue_index", repoID); err != nil { + if err := db.UpsertResourceIndex(ctx.Engine(), "issue_index", repoID); err != nil { return err } var max int64 - if _, err := sess.Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&max); err != nil { + if _, err := ctx.Engine().Select(" MAX(`index`)").Table("issue").Where("repo_id=?", repoID).Get(&max); err != nil { return err } - if _, err := sess.Exec("UPDATE `issue_index` SET max_index=? WHERE group_id=?", max, repoID); err != nil { + if _, err := ctx.Engine().Exec("UPDATE `issue_index` SET max_index=? WHERE group_id=?", max, repoID); err != nil { return err } - return sess.Commit() + return committer.Commit() } // NewIssue creates new issue with labels for repository. func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { - idx, err := GetNextResourceIndex("issue_index", repo.ID) + idx, err := db.GetNextResourceIndex("issue_index", repo.ID) if err != nil { return fmt.Errorf("generate issue index failed: %v", err) } issue.Index = idx - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + ctx, committer, err := db.TxContext() + if err != nil { return err } + defer committer.Close() - if err = newIssue(sess, issue.Poster, NewIssueOptions{ + if err = newIssue(ctx.Engine(), issue.Poster, NewIssueOptions{ Repo: repo, Issue: issue, LabelIDs: labelIDs, @@ -1034,7 +1039,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) return fmt.Errorf("newIssue: %v", err) } - if err = sess.Commit(); err != nil { + if err = committer.Commit(); err != nil { return fmt.Errorf("Commit: %v", err) } @@ -1050,7 +1055,7 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) { RepoID: repoID, Index: index, } - has, err := x.Get(issue) + has, err := db.DefaultContext().Engine().Get(issue) if err != nil { return nil, err } else if !has { @@ -1068,7 +1073,7 @@ func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) { return issue, issue.LoadAttributes() } -func getIssueByID(e Engine, id int64) (*Issue, error) { +func getIssueByID(e db.Engine, id int64) (*Issue, error) { issue := new(Issue) has, err := e.ID(id).Get(issue) if err != nil { @@ -1081,24 +1086,24 @@ func getIssueByID(e Engine, id int64) (*Issue, error) { // GetIssueWithAttrsByID returns an issue with attributes by given ID. func GetIssueWithAttrsByID(id int64) (*Issue, error) { - issue, err := getIssueByID(x, id) + issue, err := getIssueByID(db.DefaultContext().Engine(), id) if err != nil { return nil, err } - return issue, issue.loadAttributes(x) + return issue, issue.loadAttributes(db.DefaultContext().Engine()) } // GetIssueByID returns an issue by given ID. func GetIssueByID(id int64) (*Issue, error) { - return getIssueByID(x, id) + return getIssueByID(db.DefaultContext().Engine(), id) } -func getIssuesByIDs(e Engine, issueIDs []int64) ([]*Issue, error) { +func getIssuesByIDs(e db.Engine, issueIDs []int64) ([]*Issue, error) { issues := make([]*Issue, 0, 10) return issues, e.In("id", issueIDs).Find(&issues) } -func getIssueIDsByRepoID(e Engine, repoID int64) ([]int64, error) { +func getIssueIDsByRepoID(e db.Engine, repoID int64) ([]int64, error) { ids := make([]int64, 0, 10) err := e.Table("issue").Cols("id").Where("repo_id = ?", repoID).Find(&ids) return ids, err @@ -1106,12 +1111,12 @@ func getIssueIDsByRepoID(e Engine, repoID int64) ([]int64, error) { // GetIssueIDsByRepoID returns all issue ids by repo id func GetIssueIDsByRepoID(repoID int64) ([]int64, error) { - return getIssueIDsByRepoID(x, repoID) + return getIssueIDsByRepoID(db.DefaultContext().Engine(), repoID) } // GetIssuesByIDs return issues with the given IDs. func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { - return getIssuesByIDs(x, issueIDs) + return getIssuesByIDs(db.DefaultContext().Engine(), issueIDs) } // IssuesOptions represents options of an issue. @@ -1311,7 +1316,7 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) // CountIssuesByRepo map from repoID to number of issues matching the options func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") @@ -1339,7 +1344,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) { // GetRepoIDsForIssuesOptions find all repo ids for the given options func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *User) ([]int64, error) { repoIDs := make([]int64, 0, 5) - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") @@ -1359,7 +1364,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *User) ([]int64, error // Issues returns a list of issues by given conditions. func Issues(opts *IssuesOptions) ([]*Issue, error) { - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") @@ -1381,7 +1386,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { // CountIssues number return of issues by given conditions. func CountIssues(opts *IssuesOptions) (int64, error) { - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() countsSlice := make([]*struct { @@ -1406,7 +1411,7 @@ func CountIssues(opts *IssuesOptions) (int64, error) { // User permissions must be verified elsewhere if required. func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) { userIDs := make([]int64, 0, 5) - return userIDs, x.Table("comment"). + return userIDs, db.DefaultContext().Engine().Table("comment"). Cols("poster_id"). Where("issue_id = ?", issueID). And("type in (?,?,?)", CommentTypeComment, CommentTypeCode, CommentTypeReview). @@ -1416,7 +1421,7 @@ func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) { // IsUserParticipantsOfIssue return true if user is participants of an issue func IsUserParticipantsOfIssue(user *User, issue *Issue) bool { - userIDs, err := issue.getParticipantIDsByIssue(x) + userIDs, err := issue.getParticipantIDsByIssue(db.DefaultContext().Engine()) if err != nil { log.Error(err.Error()) return false @@ -1425,7 +1430,7 @@ func IsUserParticipantsOfIssue(user *User, issue *Issue) bool { } // UpdateIssueMentions updates issue-user relations for mentioned users. -func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []*User) error { +func UpdateIssueMentions(ctx *db.Context, issueID int64, mentions []*User) error { if len(mentions) == 0 { return nil } @@ -1482,6 +1487,12 @@ type IssueStatsOptions struct { IssueIDs []int64 } +const ( + // When queries are broken down in parts because of the number + // of parameters, attempt to break by this amount + maxQueryParameters = 300 +) + // GetIssueStats returns issue statistic information by given conditions. func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { if len(opts.IssueIDs) <= maxQueryParameters { @@ -1518,7 +1529,7 @@ func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, stats := &IssueStats{} countSession := func(opts *IssueStatsOptions) *xorm.Session { - sess := x. + sess := db.DefaultContext().Engine(). Where("issue.repo_id = ?", opts.RepoID) if len(opts.IssueIDs) > 0 { @@ -1612,7 +1623,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { } sess := func(cond builder.Cond) *xorm.Session { - s := x.Where(cond) + s := db.DefaultContext().Engine().Where(cond) if len(opts.LabelIDs) > 0 { s.Join("INNER", "issue_label", "issue_label.issue_id = issue.id"). In("issue_label.label_id", opts.LabelIDs) @@ -1724,7 +1735,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { // GetRepoIssueStats returns number of open and closed repository issues by given filter mode. func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen, numClosed int64) { countSession := func(isClosed, isPull bool, repoID int64) *xorm.Session { - sess := x. + sess := db.DefaultContext().Engine(). Where("is_closed = ?", isClosed). And("is_pull = ?", isPull). And("repo_id = ?", repoID) @@ -1776,7 +1787,7 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6 ID int64 UpdatedUnix int64 }, 0, limit) - err := x.Distinct("id", "updated_unix").Table("issue").Where(cond). + err := db.DefaultContext().Engine().Distinct("id", "updated_unix").Table("issue").Where(cond). OrderBy("`updated_unix` DESC").Limit(limit, start). Find(&res) if err != nil { @@ -1786,7 +1797,7 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6 ids = append(ids, r.ID) } - total, err := x.Distinct("id").Table("issue").Where(cond).Count() + total, err := db.DefaultContext().Engine().Distinct("id").Table("issue").Where(cond).Count() if err != nil { return 0, nil, err } @@ -1798,7 +1809,7 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6 // If the issue status is changed a statusChangeComment is returned // similarly if the title is changed the titleChanged bool is set to true func UpdateIssueByAPI(issue *Issue, doer *User) (statusChangeComment *Comment, titleChanged bool, err error) { - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return nil, false, err @@ -1857,7 +1868,7 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *Us return nil } - sess := x.NewSession() + sess := db.DefaultContext().NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err @@ -1883,7 +1894,7 @@ type DependencyInfo struct { } // getParticipantIDsByIssue returns all userIDs who are participated in comments of an issue and issue author -func (issue *Issue) getParticipantIDsByIssue(e Engine) ([]int64, error) { +func (issue *Issue) getParticipantIDsByIssue(e db.Engine) ([]int64, error) { if issue == nil { return nil, nil } @@ -1905,7 +1916,7 @@ func (issue *Issue) getParticipantIDsByIssue(e Engine) ([]int64, error) { } // Get Blocked By Dependencies, aka all issues this issue is blocked by. -func (issue *Issue) getBlockedByDependencies(e Engine) (issueDeps []*DependencyInfo, err error) { +func (issue *Issue) getBlockedByDependencies(e db.Engine) (issueDeps []*DependencyInfo, err error) { return issueDeps, e. Table("issue"). Join("INNER", "repository", "repository.id = issue.repo_id"). @@ -1917,7 +1928,7 @@ func (issue *Issue) getBlockedByDependencies(e Engine) (issueDeps []*DependencyI } // Get Blocking Dependencies, aka all issues this issue blocks. -func (issue *Issue) getBlockingDependencies(e Engine) (issueDeps []*DependencyInfo, err error) { +func (issue *Issue) getBlockingDependencies(e db.Engine) (issueDeps []*DependencyInfo, err error) { return issueDeps, e. Table("issue"). Join("INNER", "repository", "repository.id = issue.repo_id"). @@ -1930,15 +1941,15 @@ func (issue *Issue) getBlockingDependencies(e Engine) (issueDeps []*DependencyIn // BlockedByDependencies finds all Dependencies an issue is blocked by func (issue *Issue) BlockedByDependencies() ([]*DependencyInfo, error) { - return issue.getBlockedByDependencies(x) + return issue.getBlockedByDependencies(db.DefaultContext().Engine()) } // BlockingDependencies returns all blocking dependencies, aka all other issues a given issue blocks func (issue *Issue) BlockingDependencies() ([]*DependencyInfo, error) { - return issue.getBlockingDependencies(x) + return issue.getBlockingDependencies(db.DefaultContext().Engine()) } -func (issue *Issue) updateClosedNum(e Engine) (err error) { +func (issue *Issue) updateClosedNum(e db.Engine) (err error) { if issue.IsPull { _, err = e.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?", issue.RepoID, @@ -1958,7 +1969,7 @@ func (issue *Issue) updateClosedNum(e Engine) (err error) { } // FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database. -func (issue *Issue) FindAndUpdateIssueMentions(ctx DBContext, doer *User, content string) (mentions []*User, err error) { +func (issue *Issue) FindAndUpdateIssueMentions(ctx *db.Context, doer *User, content string) (mentions []*User, err error) { rawMentions := references.FindAllMentionsMarkdown(content) mentions, err = issue.ResolveMentionsByVisibility(ctx, doer, rawMentions) if err != nil { @@ -1972,18 +1983,18 @@ func (issue *Issue) FindAndUpdateIssueMentions(ctx DBContext, doer *User, conten // ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that // don't have access to reading it. Teams are expanded into their users, but organizations are ignored. -func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) { +func (issue *Issue) ResolveMentionsByVisibility(ctx *db.Context, doer *User, mentions []string) (users []*User, err error) { if len(mentions) == 0 { return } - if err = issue.loadRepo(ctx.e); err != nil { + if err = issue.loadRepo(ctx.Engine()); err != nil { return } resolved := make(map[string]bool, 10) var mentionTeams []string - if err := issue.Repo.getOwner(ctx.e); err != nil { + if err := issue.Repo.getOwner(ctx.Engine()); err != nil { return nil, err } @@ -2012,7 +2023,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti if issue.Repo.Owner.IsOrganization() && len(mentionTeams) > 0 { teams := make([]*Team, 0, len(mentionTeams)) - if err := ctx.e. + if err := ctx.Engine(). Join("INNER", "team_repo", "team_repo.team_id = team.id"). Where("team_repo.repo_id=?", issue.Repo.ID). In("team.lower_name", mentionTeams). @@ -2031,7 +2042,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti resolved[issue.Repo.Owner.LowerName+"/"+team.LowerName] = true continue } - has, err := ctx.e.Get(&TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype}) + has, err := ctx.Engine().Get(&TeamUnit{OrgID: issue.Repo.Owner.ID, TeamID: team.ID, Type: unittype}) if err != nil { return nil, fmt.Errorf("get team units (%d): %v", team.ID, err) } @@ -2042,7 +2053,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti } if len(checked) != 0 { teamusers := make([]*User, 0, 20) - if err := ctx.e. + if err := ctx.Engine(). Join("INNER", "team_user", "team_user.uid = `user`.id"). In("`team_user`.team_id", checked). And("`user`.is_active = ?", true). @@ -2079,7 +2090,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti } unchecked := make([]*User, 0, len(mentionUsers)) - if err := ctx.e. + if err := ctx.Engine(). Where("`user`.is_active = ?", true). And("`user`.prohibit_login = ?", false). In("`user`.lower_name", mentionUsers). @@ -2091,7 +2102,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti continue } // Normal users must have read access to the referencing issue - perm, err := getUserRepoPermission(ctx.e, issue.Repo, user) + perm, err := getUserRepoPermission(ctx.Engine(), issue.Repo, user) if err != nil { return nil, fmt.Errorf("getUserRepoPermission [%d]: %v", user.ID, err) } @@ -2106,7 +2117,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, menti // UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { - _, err := x.Table("issue"). + _, err := db.DefaultContext().Engine().Table("issue"). Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). And("original_author_id = ?", originalAuthorID). Update(map[string]interface{}{ @@ -2119,7 +2130,7 @@ func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, origina // UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID func UpdateReactionsMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, userID int64) error { - _, err := x.Table("reaction"). + _, err := db.DefaultContext().Engine().Table("reaction"). Where("original_author_id = ?", originalAuthorID). And(migratedIssueCond(gitServiceType)). Update(map[string]interface{}{ @@ -2130,7 +2141,7 @@ func UpdateReactionsMigrationsByType(gitServiceType structs.GitServiceType, orig return err } -func deleteIssuesByRepoID(sess Engine, repoID int64) (attachmentPaths []string, err error) { +func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []string, err error) { deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID}) // Delete comments and attachments |