Skip to content

Remove issue_ids conditions from IssuesOptions #24822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
10 changes: 10 additions & 0 deletions models/issues/issue_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/util"

"xorm.io/builder"
)
Expand Down Expand Up @@ -603,3 +604,12 @@ func (issues IssueList) GetApprovalCounts(ctx context.Context) (map[int64][]*Rev

return approvalCountMap, nil
}

func FindIssuesByIDs(ctx context.Context, ids []int64, isPull util.OptionalBool) (IssueList, error) {
sess := db.GetEngine(ctx).In("id", ids)
if !isPull.IsNone() {
sess.And("is_pull=?", isPull.IsTrue())
}
var issues IssueList
return issues, sess.Find(&issues)
}
237 changes: 120 additions & 117 deletions models/issues/issue_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ type IssuesOptions struct { //nolint
ExcludedLabelNames []string
IncludeMilestones []string
SortType string
IssueIDs []int64
UpdatedAfterUnix int64
UpdatedBeforeUnix int64
// IssueIDs []int64
UpdatedAfterUnix int64
UpdatedBeforeUnix int64
// prioritize issues from this repo
PriorityRepoID int64
IsArchived util.OptionalBool
Org *organization.Organization // issues permission scope
Team *organization.Team // issues permission scope
User *user_model.User // issues permission scope

Keyword string
DontSearchComment bool // whether to search in comments
}

// applySorts sort an issues-related session based on the provided
Expand Down Expand Up @@ -111,6 +114,29 @@ func applyLimit(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
return sess
}

func applyKeywordCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if opts.Keyword == "" {
return sess
}

return sess.Where(
builder.Or(
db.BuildCaseInsensitiveLike("issue.name", opts.Keyword),
db.BuildCaseInsensitiveLike("issue.content", opts.Keyword),
builder.If(!opts.DontSearchComment,
builder.In("issue.id", builder.Select("issue_id").
From("comment").
Where(builder.And(
builder.Expr("comment.issue_id = issue.id"),
builder.Eq{"type": CommentTypeComment},
db.BuildCaseInsensitiveLike("content", opts.Keyword),
)),
),
),
),
)
}

func applyLabelsCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if len(opts.LabelIDs) > 0 {
if opts.LabelIDs[0] == 0 {
Expand Down Expand Up @@ -157,93 +183,89 @@ func applyMilestoneCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Sess

func applyRepoConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if len(opts.RepoIDs) == 1 {
opts.RepoCond = builder.Eq{"issue.repo_id": opts.RepoIDs[0]}
sess.And(builder.Eq{"issue.repo_id": opts.RepoIDs[0]})
} else if len(opts.RepoIDs) > 1 {
opts.RepoCond = builder.In("issue.repo_id", opts.RepoIDs)
}
if opts.RepoCond != nil {
sess.And(builder.In("issue.repo_id", opts.RepoIDs))
} else if opts.RepoCond != nil {
sess.And(opts.RepoCond)
}
return sess
}

func applyConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if len(opts.IssueIDs) > 0 {
sess.In("issue.id", opts.IssueIDs)
func applyIsPullCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if !opts.IsPull.IsNone() {
sess.And("issue.is_pull=?", opts.IsPull.IsTrue())
}
return sess
}

applyRepoConditions(sess, opts)

if !opts.IsClosed.IsNone() {
sess.And("issue.is_closed=?", opts.IsClosed.IsTrue())
func applyUserCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if opts.User != nil {
sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()))
}
return sess
}

if opts.AssigneeID > 0 {
applyAssigneeCondition(sess, opts.AssigneeID)
} else if opts.AssigneeID == db.NoConditionID {
sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)")
func applyProjectConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if opts.ProjectID > 0 {
sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id").
And("project_issue.project_id=?", opts.ProjectID)
} else if opts.ProjectID == db.NoConditionID { // show those that are in no project
sess.And(builder.NotIn("issue.id", builder.Select("issue_id").From("project_issue")))
}

if opts.PosterID > 0 {
applyPosterCondition(sess, opts.PosterID)
if opts.ProjectBoardID != 0 {
if opts.ProjectBoardID > 0 {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
} else {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0}))
}
}

if opts.MentionedID > 0 {
applyMentionedCondition(sess, opts.MentionedID)
}
return sess
}

if opts.ReviewRequestedID > 0 {
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)
}
func applyConditions(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
applyRepoConditions(sess, opts)

if opts.ReviewedID > 0 {
applyReviewedCondition(sess, opts.ReviewedID)
if opts.IsArchived != util.OptionalBoolNone {
sess.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()})
}

if opts.SubscriberID > 0 {
applySubscribedCondition(sess, opts.SubscriberID)
if !opts.IsClosed.IsNone() {
sess.And("issue.is_closed=?", opts.IsClosed.IsTrue())
}

applyIsPullCondition(sess, opts)

applyMilestoneCondition(sess, opts)

applyPosterCondition(sess, opts.PosterID)

if opts.UpdatedAfterUnix != 0 {
sess.And(builder.Gte{"issue.updated_unix": opts.UpdatedAfterUnix})
}
if opts.UpdatedBeforeUnix != 0 {
sess.And(builder.Lte{"issue.updated_unix": opts.UpdatedBeforeUnix})
}

if opts.ProjectID > 0 {
sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id").
And("project_issue.project_id=?", opts.ProjectID)
} else if opts.ProjectID == db.NoConditionID { // show those that are in no project
sess.And(builder.NotIn("issue.id", builder.Select("issue_id").From("project_issue")))
}
applyAssigneeCondition(sess, opts.AssigneeID)

if opts.ProjectBoardID != 0 {
if opts.ProjectBoardID > 0 {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": opts.ProjectBoardID}))
} else {
sess.In("issue.id", builder.Select("issue_id").From("project_issue").Where(builder.Eq{"project_board_id": 0}))
}
}
applyMentionedCondition(sess, opts.MentionedID)

switch opts.IsPull {
case util.OptionalBoolTrue:
sess.And("issue.is_pull=?", true)
case util.OptionalBoolFalse:
sess.And("issue.is_pull=?", false)
}
applyReviewRequestedCondition(sess, opts.ReviewRequestedID)

if opts.IsArchived != util.OptionalBoolNone {
sess.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()})
}
applyReviewedCondition(sess, opts.ReviewedID)

applySubscribedCondition(sess, opts)

applyProjectConditions(sess, opts)

applyLabelsCondition(sess, opts)

if opts.User != nil {
sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()))
}
applyUserCondition(sess, opts)

applyKeywordCondition(sess, opts)

return sess
}
Expand Down Expand Up @@ -323,30 +345,50 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organizati
}

func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session {
return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", assigneeID)
switch assigneeID {
case 0:
return sess
case db.NoConditionID:
return sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)")
default:
return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
And("issue_assignees.assignee_id = ?", assigneeID)
}
}

func applyPosterCondition(sess *xorm.Session, posterID int64) *xorm.Session {
return sess.And("issue.poster_id=?", posterID)
if posterID > 0 {
return sess.And("issue.poster_id=?", posterID)
}
return sess
}

func applyMentionedCondition(sess *xorm.Session, mentionedID int64) *xorm.Session {
return sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", mentionedID)
if mentionedID > 0 {
return sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
And("issue_user.is_mentioned = ?", true).
And("issue_user.uid = ?", mentionedID)
}
return sess
}

func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) *xorm.Session {
return sess.Join("INNER", []string{"review", "r"}, "issue.id = r.issue_id").
And("issue.poster_id <> ?", reviewRequestedID).
And("r.type = ?", ReviewTypeRequest).
And("r.reviewer_id = ? and r.id in (select max(id) from review where issue_id = r.issue_id and reviewer_id = r.reviewer_id and type in (?, ?, ?))"+
" or r.reviewer_team_id in (select team_id from team_user where uid = ?)",
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
if reviewRequestedID > 0 {
return sess.Join("INNER", []string{"review", "r"}, "issue.id = r.issue_id").
And("issue.poster_id <> ?", reviewRequestedID).
And("r.type = ?", ReviewTypeRequest).
And("r.reviewer_id = ? and r.id in (select max(id) from review where issue_id = r.issue_id and reviewer_id = r.reviewer_id and type in (?, ?, ?))"+
" or r.reviewer_team_id in (select team_id from team_user where uid = ?)",
reviewRequestedID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, reviewRequestedID)
}
return sess
}

func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session {
if reviewedID == 0 {
return sess
}

// Query for pull requests where you are a reviewer or commenter, excluding
// any pull requests already returned by the the review requested filter.
notPoster := builder.Neq{"issue.poster_id": reviewedID}
Expand Down Expand Up @@ -376,31 +418,35 @@ func applyReviewedCondition(sess *xorm.Session, reviewedID int64) *xorm.Session
return sess.And(notPoster, builder.Or(reviewed, commented))
}

func applySubscribedCondition(sess *xorm.Session, subscriberID int64) *xorm.Session {
func applySubscribedCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
if opts.SubscriberID == 0 {
return sess
}

return sess.And(
builder.
NotIn("issue.id",
builder.Select("issue_id").
From("issue_watch").
Where(builder.Eq{"is_watching": false, "user_id": subscriberID}),
Where(builder.Eq{"is_watching": false, "user_id": opts.SubscriberID}),
),
).And(
builder.Or(
builder.In("issue.id", builder.
Select("issue_id").
From("issue_watch").
Where(builder.Eq{"is_watching": true, "user_id": subscriberID}),
Where(builder.Eq{"is_watching": true, "user_id": opts.SubscriberID}),
),
builder.In("issue.id", builder.
Select("issue_id").
From("comment").
Where(builder.Eq{"poster_id": subscriberID}),
Where(builder.Eq{"poster_id": opts.SubscriberID}),
),
builder.Eq{"issue.poster_id": subscriberID},
builder.Eq{"issue.poster_id": opts.SubscriberID},
builder.In("issue.repo_id", builder.
Select("id").
From("watch").
Where(builder.And(builder.Eq{"user_id": subscriberID},
Where(builder.And(builder.Eq{"user_id": opts.SubscriberID},
builder.In("mode", repo_model.WatchModeNormal, repo_model.WatchModeAuto))),
),
),
Expand Down Expand Up @@ -428,7 +474,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
}

// Issues returns a list of issues by given conditions.
func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) {
func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) {
sess := db.GetEngine(ctx).
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
applyLimit(sess, opts)
Expand All @@ -446,46 +492,3 @@ func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) {

return issues, nil
}

// SearchIssueIDsByKeyword search issues on database
func SearchIssueIDsByKeyword(ctx context.Context, kw string, repoIDs []int64, limit, start int) (int64, []int64, error) {
repoCond := builder.In("repo_id", repoIDs)
subQuery := builder.Select("id").From("issue").Where(repoCond)
cond := builder.And(
repoCond,
builder.Or(
db.BuildCaseInsensitiveLike("name", kw),
db.BuildCaseInsensitiveLike("content", kw),
builder.In("id", builder.Select("issue_id").
From("comment").
Where(builder.And(
builder.Eq{"type": CommentTypeComment},
builder.In("issue_id", subQuery),
db.BuildCaseInsensitiveLike("content", kw),
)),
),
),
)

ids := make([]int64, 0, limit)
res := make([]struct {
ID int64
UpdatedUnix int64
}, 0, limit)
err := db.GetEngine(ctx).Distinct("id", "updated_unix").Table("issue").Where(cond).
OrderBy("`updated_unix` DESC").Limit(limit, start).
Find(&res)
if err != nil {
return 0, nil, err
}
for _, r := range res {
ids = append(ids, r.ID)
}

total, err := db.GetEngine(ctx).Distinct("id").Table("issue").Where(cond).Count()
if err != nil {
return 0, nil, err
}

return total, ids, nil
}
Loading