Bug fixes for Issues filters (#413)
Correctly handle simultaneous assignee/poster filters, and conflicting assignee filters
This commit is contained in:
		
					parent
					
						
							
								8a4161c723
							
						
					
				
			
			
				commit
				
					
						d0932ef147
					
				
			
		
					 3 changed files with 76 additions and 88 deletions
				
			
		| 
						 | 
					@ -855,15 +855,14 @@ func GetIssueByID(id int64) (*Issue, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IssuesOptions represents options of an issue.
 | 
					// IssuesOptions represents options of an issue.
 | 
				
			||||||
type IssuesOptions struct {
 | 
					type IssuesOptions struct {
 | 
				
			||||||
	UserID      int64
 | 
					 | 
				
			||||||
	AssigneeID  int64
 | 
					 | 
				
			||||||
	RepoID      int64
 | 
						RepoID      int64
 | 
				
			||||||
 | 
						AssigneeID  int64
 | 
				
			||||||
	PosterID    int64
 | 
						PosterID    int64
 | 
				
			||||||
 | 
						MentionedID int64
 | 
				
			||||||
	MilestoneID int64
 | 
						MilestoneID int64
 | 
				
			||||||
	RepoIDs     []int64
 | 
						RepoIDs     []int64
 | 
				
			||||||
	Page        int
 | 
						Page        int
 | 
				
			||||||
	IsClosed    bool
 | 
						IsClosed    bool
 | 
				
			||||||
	IsMention   bool
 | 
					 | 
				
			||||||
	IsPull      bool
 | 
						IsPull      bool
 | 
				
			||||||
	Labels      string
 | 
						Labels      string
 | 
				
			||||||
	SortType    string
 | 
						SortType    string
 | 
				
			||||||
| 
						 | 
					@ -887,10 +886,18 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.AssigneeID > 0 {
 | 
						if opts.AssigneeID > 0 {
 | 
				
			||||||
		sess.And("issue.assignee_id=?", opts.AssigneeID)
 | 
							sess.And("issue.assignee_id=?", opts.AssigneeID)
 | 
				
			||||||
	} else if opts.PosterID > 0 {
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.PosterID > 0 {
 | 
				
			||||||
		sess.And("issue.poster_id=?", opts.PosterID)
 | 
							sess.And("issue.poster_id=?", opts.PosterID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.MentionedID > 0 {
 | 
				
			||||||
 | 
							sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
				
			||||||
 | 
								And("issue_user.is_mentioned = ?", true).
 | 
				
			||||||
 | 
								And("issue_user.uid = ?", opts.MentionedID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.MilestoneID > 0 {
 | 
						if opts.MilestoneID > 0 {
 | 
				
			||||||
		sess.And("issue.milestone_id=?", opts.MilestoneID)
 | 
							sess.And("issue.milestone_id=?", opts.MilestoneID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -926,16 +933,6 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.IsMention {
 | 
					 | 
				
			||||||
		sess.
 | 
					 | 
				
			||||||
			Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
					 | 
				
			||||||
			And("issue_user.is_mentioned = ?", true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if opts.UserID > 0 {
 | 
					 | 
				
			||||||
			sess.And("issue_user.uid = ?", opts.UserID)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	issues := make([]*Issue, 0, setting.UI.IssuePagingNum)
 | 
						issues := make([]*Issue, 0, setting.UI.IssuePagingNum)
 | 
				
			||||||
	if err := sess.Find(&issues); err != nil {
 | 
						if err := sess.Find(&issues); err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("Find: %v", err)
 | 
							return nil, fmt.Errorf("Find: %v", err)
 | 
				
			||||||
| 
						 | 
					@ -1156,11 +1153,11 @@ func parseCountResult(results []map[string][]byte) int64 {
 | 
				
			||||||
// IssueStatsOptions contains parameters accepted by GetIssueStats.
 | 
					// IssueStatsOptions contains parameters accepted by GetIssueStats.
 | 
				
			||||||
type IssueStatsOptions struct {
 | 
					type IssueStatsOptions struct {
 | 
				
			||||||
	RepoID      int64
 | 
						RepoID      int64
 | 
				
			||||||
	UserID      int64
 | 
					 | 
				
			||||||
	Labels      string
 | 
						Labels      string
 | 
				
			||||||
	MilestoneID int64
 | 
						MilestoneID int64
 | 
				
			||||||
	AssigneeID  int64
 | 
						AssigneeID  int64
 | 
				
			||||||
	FilterMode  int
 | 
						MentionedID int64
 | 
				
			||||||
 | 
						PosterID    int64
 | 
				
			||||||
	IsPull      bool
 | 
						IsPull      bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1191,43 +1188,25 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats {
 | 
				
			||||||
			sess.And("assignee_id = ?", opts.AssigneeID)
 | 
								sess.And("assignee_id = ?", opts.AssigneeID)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if opts.PosterID > 0 {
 | 
				
			||||||
 | 
								sess.And("poster_id = ?", opts.PosterID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if opts.MentionedID > 0 {
 | 
				
			||||||
 | 
								sess.Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
				
			||||||
 | 
								And("issue_user.uid = ?", opts.MentionedID).
 | 
				
			||||||
 | 
								And("issue_user.is_mentioned = ?", true)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return sess
 | 
							return sess
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch opts.FilterMode {
 | 
						stats.OpenCount, _ = countSession(opts).
 | 
				
			||||||
	case FilterModeAll, FilterModeAssign:
 | 
							And("is_closed = ?", false).
 | 
				
			||||||
		stats.OpenCount, _ = countSession(opts).
 | 
							Count(&Issue{})
 | 
				
			||||||
			And("is_closed = ?", false).
 | 
						stats.ClosedCount, _ = countSession(opts).
 | 
				
			||||||
			Count(&Issue{})
 | 
							And("is_closed = ?", true).
 | 
				
			||||||
 | 
							Count(&Issue{})
 | 
				
			||||||
		stats.ClosedCount, _ = countSession(opts).
 | 
					 | 
				
			||||||
			And("is_closed = ?", true).
 | 
					 | 
				
			||||||
			Count(&Issue{})
 | 
					 | 
				
			||||||
	case FilterModeCreate:
 | 
					 | 
				
			||||||
		stats.OpenCount, _ = countSession(opts).
 | 
					 | 
				
			||||||
			And("poster_id = ?", opts.UserID).
 | 
					 | 
				
			||||||
			And("is_closed = ?", false).
 | 
					 | 
				
			||||||
			Count(&Issue{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stats.ClosedCount, _ = countSession(opts).
 | 
					 | 
				
			||||||
			And("poster_id = ?", opts.UserID).
 | 
					 | 
				
			||||||
			And("is_closed = ?", true).
 | 
					 | 
				
			||||||
			Count(&Issue{})
 | 
					 | 
				
			||||||
	case FilterModeMention:
 | 
					 | 
				
			||||||
		stats.OpenCount, _ = countSession(opts).
 | 
					 | 
				
			||||||
			Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
					 | 
				
			||||||
			And("issue_user.uid = ?", opts.UserID).
 | 
					 | 
				
			||||||
			And("issue_user.is_mentioned = ?", true).
 | 
					 | 
				
			||||||
			And("issue.is_closed = ?", false).
 | 
					 | 
				
			||||||
			Count(&Issue{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stats.ClosedCount, _ = countSession(opts).
 | 
					 | 
				
			||||||
			Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
					 | 
				
			||||||
			And("issue_user.uid = ?", opts.UserID).
 | 
					 | 
				
			||||||
			And("issue_user.is_mentioned = ?", true).
 | 
					 | 
				
			||||||
			And("issue.is_closed = ?", true).
 | 
					 | 
				
			||||||
			Count(&Issue{})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return stats
 | 
						return stats
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,38 +130,42 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		assigneeID = ctx.QueryInt64("assignee")
 | 
							assigneeID = ctx.QueryInt64("assignee")
 | 
				
			||||||
		posterID   int64
 | 
							posterID     int64
 | 
				
			||||||
 | 
							mentionedID  int64
 | 
				
			||||||
 | 
							forceEmpty   bool
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	filterMode := models.FilterModeAll
 | 
					 | 
				
			||||||
	switch viewType {
 | 
						switch viewType {
 | 
				
			||||||
	case "assigned":
 | 
						case "assigned":
 | 
				
			||||||
		filterMode = models.FilterModeAssign
 | 
							if assigneeID > 0 && ctx.User.ID != assigneeID {
 | 
				
			||||||
		assigneeID = ctx.User.ID
 | 
								// two different assignees, must be empty
 | 
				
			||||||
 | 
								forceEmpty = true
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								assigneeID = ctx.User.ID
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	case "created_by":
 | 
						case "created_by":
 | 
				
			||||||
		filterMode = models.FilterModeCreate
 | 
					 | 
				
			||||||
		posterID = ctx.User.ID
 | 
							posterID = ctx.User.ID
 | 
				
			||||||
	case "mentioned":
 | 
						case "mentioned":
 | 
				
			||||||
		filterMode = models.FilterModeMention
 | 
							mentionedID = ctx.User.ID
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var uid int64 = -1
 | 
					 | 
				
			||||||
	if ctx.IsSigned {
 | 
					 | 
				
			||||||
		uid = ctx.User.ID
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
	selectLabels := ctx.Query("labels")
 | 
						selectLabels := ctx.Query("labels")
 | 
				
			||||||
	milestoneID := ctx.QueryInt64("milestone")
 | 
						milestoneID := ctx.QueryInt64("milestone")
 | 
				
			||||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
						isShowClosed := ctx.Query("state") == "closed"
 | 
				
			||||||
	issueStats := models.GetIssueStats(&models.IssueStatsOptions{
 | 
					
 | 
				
			||||||
		RepoID:      repo.ID,
 | 
						var issueStats *models.IssueStats
 | 
				
			||||||
		UserID:      uid,
 | 
						if forceEmpty {
 | 
				
			||||||
		Labels:      selectLabels,
 | 
							issueStats = &models.IssueStats{}
 | 
				
			||||||
		MilestoneID: milestoneID,
 | 
						} else {
 | 
				
			||||||
		AssigneeID:  assigneeID,
 | 
							issueStats = models.GetIssueStats(&models.IssueStatsOptions{
 | 
				
			||||||
		FilterMode:  filterMode,
 | 
								RepoID:      repo.ID,
 | 
				
			||||||
		IsPull:      isPullList,
 | 
								Labels:      selectLabels,
 | 
				
			||||||
	})
 | 
								MilestoneID: milestoneID,
 | 
				
			||||||
 | 
								AssigneeID:  assigneeID,
 | 
				
			||||||
 | 
								MentionedID: mentionedID,
 | 
				
			||||||
 | 
								IsPull:      isPullList,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page := ctx.QueryInt("page")
 | 
						page := ctx.QueryInt("page")
 | 
				
			||||||
	if page <= 1 {
 | 
						if page <= 1 {
 | 
				
			||||||
| 
						 | 
					@ -177,22 +181,28 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
	pager := paginater.New(total, setting.UI.IssuePagingNum, page, 5)
 | 
						pager := paginater.New(total, setting.UI.IssuePagingNum, page, 5)
 | 
				
			||||||
	ctx.Data["Page"] = pager
 | 
						ctx.Data["Page"] = pager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	issues, err := models.Issues(&models.IssuesOptions{
 | 
					
 | 
				
			||||||
		UserID:      uid,
 | 
						var issues []*models.Issue
 | 
				
			||||||
		AssigneeID:  assigneeID,
 | 
						if forceEmpty {
 | 
				
			||||||
		RepoID:      repo.ID,
 | 
							issues = []*models.Issue{}
 | 
				
			||||||
		PosterID:    posterID,
 | 
						} else {
 | 
				
			||||||
		MilestoneID: milestoneID,
 | 
							var err error
 | 
				
			||||||
		Page:        pager.Current(),
 | 
							issues, err = models.Issues(&models.IssuesOptions{
 | 
				
			||||||
		IsClosed:    isShowClosed,
 | 
								AssigneeID:  assigneeID,
 | 
				
			||||||
		IsMention:   filterMode == models.FilterModeMention,
 | 
								RepoID:      repo.ID,
 | 
				
			||||||
		IsPull:      isPullList,
 | 
								PosterID:    posterID,
 | 
				
			||||||
		Labels:      selectLabels,
 | 
								MentionedID: mentionedID,
 | 
				
			||||||
		SortType:    sortType,
 | 
								MilestoneID: milestoneID,
 | 
				
			||||||
	})
 | 
								Page:        pager.Current(),
 | 
				
			||||||
	if err != nil {
 | 
								IsClosed:    isShowClosed,
 | 
				
			||||||
		ctx.Handle(500, "Issues", err)
 | 
								IsPull:      isPullList,
 | 
				
			||||||
		return
 | 
								Labels:      selectLabels,
 | 
				
			||||||
 | 
								SortType:    sortType,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "Issues", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get issue-user relations.
 | 
						// Get issue-user relations.
 | 
				
			||||||
| 
						 | 
					@ -233,7 +243,7 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if viewType == "assigned" {
 | 
						if ctx.QueryInt64("assignee") == 0 {
 | 
				
			||||||
		assigneeID = 0 // Reset ID to prevent unexpected selection of assignee.
 | 
							assigneeID = 0 // Reset ID to prevent unexpected selection of assignee.
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -272,7 +272,6 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get issues.
 | 
						// Get issues.
 | 
				
			||||||
	issues, err := models.Issues(&models.IssuesOptions{
 | 
						issues, err := models.Issues(&models.IssuesOptions{
 | 
				
			||||||
		UserID:     ctxUser.ID,
 | 
					 | 
				
			||||||
		AssigneeID: assigneeID,
 | 
							AssigneeID: assigneeID,
 | 
				
			||||||
		RepoID:     repoID,
 | 
							RepoID:     repoID,
 | 
				
			||||||
		PosterID:   posterID,
 | 
							PosterID:   posterID,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue