mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 22:28:05 +01:00 
			
		
		
		
	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
					
				| @ -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 { |  | ||||||
| 	case FilterModeAll, FilterModeAssign: |  | ||||||
| 	stats.OpenCount, _ = countSession(opts). | 	stats.OpenCount, _ = countSession(opts). | ||||||
| 		And("is_closed = ?", false). | 		And("is_closed = ?", false). | ||||||
| 		Count(&Issue{}) | 		Count(&Issue{}) | ||||||
| 
 |  | ||||||
| 	stats.ClosedCount, _ = countSession(opts). | 	stats.ClosedCount, _ = countSession(opts). | ||||||
| 		And("is_closed = ?", true). | 		And("is_closed = ?", true). | ||||||
| 		Count(&Issue{}) | 		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 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -131,37 +131,41 @@ 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 { | ||||||
|  | 			// two different assignees, must be empty | ||||||
|  | 			forceEmpty = true | ||||||
|  | 		} else { | ||||||
| 			assigneeID = ctx.User.ID | 			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{ | 
 | ||||||
|  | 	var issueStats *models.IssueStats | ||||||
|  | 	if forceEmpty { | ||||||
|  | 		issueStats = &models.IssueStats{} | ||||||
|  | 	} else { | ||||||
|  | 		issueStats = models.GetIssueStats(&models.IssueStatsOptions{ | ||||||
| 			RepoID:      repo.ID, | 			RepoID:      repo.ID, | ||||||
| 		UserID:      uid, |  | ||||||
| 			Labels:      selectLabels, | 			Labels:      selectLabels, | ||||||
| 			MilestoneID: milestoneID, | 			MilestoneID: milestoneID, | ||||||
| 			AssigneeID:  assigneeID, | 			AssigneeID:  assigneeID, | ||||||
| 		FilterMode:  filterMode, | 			MentionedID: mentionedID, | ||||||
| 			IsPull:      isPullList, | 			IsPull:      isPullList, | ||||||
| 		}) | 		}) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	page := ctx.QueryInt("page") | 	page := ctx.QueryInt("page") | ||||||
| 	if page <= 1 { | 	if page <= 1 { | ||||||
| @ -177,15 +181,20 @@ 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 | ||||||
|  | 	if forceEmpty { | ||||||
|  | 		issues = []*models.Issue{} | ||||||
|  | 	} else { | ||||||
|  | 		var err error | ||||||
|  | 		issues, err = models.Issues(&models.IssuesOptions{ | ||||||
| 			AssigneeID:  assigneeID, | 			AssigneeID:  assigneeID, | ||||||
| 			RepoID:      repo.ID, | 			RepoID:      repo.ID, | ||||||
| 			PosterID:    posterID, | 			PosterID:    posterID, | ||||||
|  | 			MentionedID: mentionedID, | ||||||
| 			MilestoneID: milestoneID, | 			MilestoneID: milestoneID, | ||||||
| 			Page:        pager.Current(), | 			Page:        pager.Current(), | ||||||
| 			IsClosed:    isShowClosed, | 			IsClosed:    isShowClosed, | ||||||
| 		IsMention:   filterMode == models.FilterModeMention, |  | ||||||
| 			IsPull:      isPullList, | 			IsPull:      isPullList, | ||||||
| 			Labels:      selectLabels, | 			Labels:      selectLabels, | ||||||
| 			SortType:    sortType, | 			SortType:    sortType, | ||||||
| @ -194,6 +203,7 @@ func Issues(ctx *context.Context) { | |||||||
| 			ctx.Handle(500, "Issues", err) | 			ctx.Handle(500, "Issues", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// Get issue-user relations. | 	// Get issue-user relations. | ||||||
| 	pairs, err := models.GetIssueUsers(repo.ID, posterID, isShowClosed) | 	pairs, err := models.GetIssueUsers(repo.ID, posterID, isShowClosed) | ||||||
| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user