Fix assigned issues dashboard (#920)
* Fix assigned/created issues in dashboard. (#3560) * Fix assigned/created issues in dashboard. * Use GetUserIssueStats for getting all Dashboard stats. * Use gofmt to format the file properly. * Replace &Issue{} with new(Issue). * Check if user has access to given repository. * Remove unnecessary filtering of issues. * Return 404 error if invalid repository is given. * Use correct number of issues in paginater. * fix issues on dashboard
This commit is contained in:
		
							parent
							
								
									3a91ac51a9
								
							
						
					
					
						commit
						7a9a5c8a69
					
				
					 4 changed files with 181 additions and 123 deletions
				
			
		| 
						 | 
					@ -1184,7 +1184,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error {
 | 
				
			||||||
// IssueStats represents issue statistic information.
 | 
					// IssueStats represents issue statistic information.
 | 
				
			||||||
type IssueStats struct {
 | 
					type IssueStats struct {
 | 
				
			||||||
	OpenCount, ClosedCount int64
 | 
						OpenCount, ClosedCount int64
 | 
				
			||||||
	AllCount               int64
 | 
						YourRepositoriesCount  int64
 | 
				
			||||||
	AssignCount            int64
 | 
						AssignCount            int64
 | 
				
			||||||
	CreateCount            int64
 | 
						CreateCount            int64
 | 
				
			||||||
	MentionCount           int64
 | 
						MentionCount           int64
 | 
				
			||||||
| 
						 | 
					@ -1210,6 +1210,7 @@ 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 {
 | 
				
			||||||
 | 
						FilterMode  int
 | 
				
			||||||
	RepoID      int64
 | 
						RepoID      int64
 | 
				
			||||||
	Labels      string
 | 
						Labels      string
 | 
				
			||||||
	MilestoneID int64
 | 
						MilestoneID int64
 | 
				
			||||||
| 
						 | 
					@ -1265,19 +1266,41 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	stats.OpenCount, err = countSession(opts).
 | 
						switch opts.FilterMode {
 | 
				
			||||||
		And("is_closed = ?", false).
 | 
						case FilterModeAll, FilterModeAssign:
 | 
				
			||||||
		Count(&Issue{})
 | 
							stats.OpenCount, err = countSession(opts).
 | 
				
			||||||
	if err != nil {
 | 
								And("is_closed = ?", false).
 | 
				
			||||||
		return nil, err
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stats.ClosedCount, err = countSession(opts).
 | 
				
			||||||
 | 
								And("is_closed = ?", true).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
						case FilterModeCreate:
 | 
				
			||||||
 | 
							stats.OpenCount, err = countSession(opts).
 | 
				
			||||||
 | 
								And("poster_id = ?", opts.PosterID).
 | 
				
			||||||
 | 
								And("is_closed = ?", false).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stats.ClosedCount, err = countSession(opts).
 | 
				
			||||||
 | 
								And("poster_id = ?", opts.PosterID).
 | 
				
			||||||
 | 
								And("is_closed = ?", true).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
						case FilterModeMention:
 | 
				
			||||||
 | 
							stats.OpenCount, err = countSession(opts).
 | 
				
			||||||
 | 
								Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
				
			||||||
 | 
								And("issue_user.uid = ?", opts.PosterID).
 | 
				
			||||||
 | 
								And("issue_user.is_mentioned = ?", true).
 | 
				
			||||||
 | 
								And("issue.is_closed = ?", false).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stats.ClosedCount, err = countSession(opts).
 | 
				
			||||||
 | 
								Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
 | 
				
			||||||
 | 
								And("issue_user.uid = ?", opts.PosterID).
 | 
				
			||||||
 | 
								And("issue_user.is_mentioned = ?", true).
 | 
				
			||||||
 | 
								And("issue.is_closed = ?", true).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	stats.ClosedCount, err = countSession(opts).
 | 
						return stats, err
 | 
				
			||||||
		And("is_closed = ?", true).
 | 
					 | 
				
			||||||
		Count(&Issue{})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return stats, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
 | 
					// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
 | 
				
			||||||
| 
						 | 
					@ -1298,29 +1321,39 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
 | 
				
			||||||
		return sess
 | 
							return sess
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stats.AssignCount, _ = countSession(false, isPull, repoID, repoIDs).
 | 
						stats.AssignCount, _ = countSession(false, isPull, repoID, nil).
 | 
				
			||||||
		And("assignee_id = ?", uid).
 | 
							And("assignee_id = ?", uid).
 | 
				
			||||||
		Count(&Issue{})
 | 
							Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stats.CreateCount, _ = countSession(false, isPull, repoID, repoIDs).
 | 
						stats.CreateCount, _ = countSession(false, isPull, repoID, nil).
 | 
				
			||||||
		And("poster_id = ?", uid).
 | 
							And("poster_id = ?", uid).
 | 
				
			||||||
		Count(&Issue{})
 | 
							Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	openCountSession := countSession(false, isPull, repoID, repoIDs)
 | 
						stats.YourRepositoriesCount, _ = countSession(false, isPull, repoID, repoIDs).
 | 
				
			||||||
	closedCountSession := countSession(true, isPull, repoID, repoIDs)
 | 
							Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch filterMode {
 | 
						switch filterMode {
 | 
				
			||||||
 | 
						case FilterModeAll:
 | 
				
			||||||
 | 
							stats.OpenCount, _ = countSession(false, isPull, repoID, repoIDs).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
							stats.ClosedCount, _ = countSession(true, isPull, repoID, repoIDs).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
	case FilterModeAssign:
 | 
						case FilterModeAssign:
 | 
				
			||||||
		openCountSession.And("assignee_id = ?", uid)
 | 
							stats.OpenCount, _ = countSession(false, isPull, repoID, nil).
 | 
				
			||||||
		closedCountSession.And("assignee_id = ?", uid)
 | 
								And("assignee_id = ?", uid).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
							stats.ClosedCount, _ = countSession(true, isPull, repoID, nil).
 | 
				
			||||||
 | 
								And("assignee_id = ?", uid).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
	case FilterModeCreate:
 | 
						case FilterModeCreate:
 | 
				
			||||||
		openCountSession.And("poster_id = ?", uid)
 | 
							stats.OpenCount, _ = countSession(false, isPull, repoID, nil).
 | 
				
			||||||
		closedCountSession.And("poster_id = ?", uid)
 | 
								And("poster_id = ?", uid).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
 | 
							stats.ClosedCount, _ = countSession(true, isPull, repoID, nil).
 | 
				
			||||||
 | 
								And("poster_id = ?", uid).
 | 
				
			||||||
 | 
								Count(new(Issue))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stats.OpenCount, _ = openCountSession.Count(&Issue{})
 | 
					 | 
				
			||||||
	stats.ClosedCount, _ = closedCountSession.Count(&Issue{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return stats
 | 
						return stats
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1347,8 +1380,8 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
 | 
				
			||||||
		closedCountSession.And("poster_id = ?", uid)
 | 
							closedCountSession.And("poster_id = ?", uid)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	openResult, _ := openCountSession.Count(&Issue{})
 | 
						openResult, _ := openCountSession.Count(new(Issue))
 | 
				
			||||||
	closedResult, _ := closedCountSession.Count(&Issue{})
 | 
						closedResult, _ := closedCountSession.Count(new(Issue))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return openResult, closedResult
 | 
						return openResult, closedResult
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/url"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,37 +107,17 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	viewType := ctx.Query("type")
 | 
						viewType := ctx.Query("type")
 | 
				
			||||||
	sortType := ctx.Query("sort")
 | 
						sortType := ctx.Query("sort")
 | 
				
			||||||
	types := []string{"assigned", "created_by", "mentioned"}
 | 
						types := []string{"all", "assigned", "created_by", "mentioned"}
 | 
				
			||||||
	if !com.IsSliceContainsStr(types, viewType) {
 | 
						if !com.IsSliceContainsStr(types, viewType) {
 | 
				
			||||||
		viewType = "all"
 | 
							viewType = "all"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Must sign in to see issues about you.
 | 
					 | 
				
			||||||
	if viewType != "all" && !ctx.IsSigned {
 | 
					 | 
				
			||||||
		ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
 | 
					 | 
				
			||||||
		ctx.Redirect(setting.AppSubURL + "/user/login")
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		assigneeID  = ctx.QueryInt64("assignee")
 | 
							assigneeID  = ctx.QueryInt64("assignee")
 | 
				
			||||||
		posterID    int64
 | 
							posterID    int64
 | 
				
			||||||
		mentionedID int64
 | 
							mentionedID int64
 | 
				
			||||||
		forceEmpty  bool
 | 
							forceEmpty  bool
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	switch viewType {
 | 
					 | 
				
			||||||
	case "assigned":
 | 
					 | 
				
			||||||
		if assigneeID > 0 && ctx.User.ID != assigneeID {
 | 
					 | 
				
			||||||
			// two different assignees, must be empty
 | 
					 | 
				
			||||||
			forceEmpty = true
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			assigneeID = ctx.User.ID
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	case "created_by":
 | 
					 | 
				
			||||||
		posterID = ctx.User.ID
 | 
					 | 
				
			||||||
	case "mentioned":
 | 
					 | 
				
			||||||
		mentionedID = ctx.User.ID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo := ctx.Repo.Repository
 | 
						repo := ctx.Repo.Repository
 | 
				
			||||||
	selectLabels := ctx.Query("labels")
 | 
						selectLabels := ctx.Query("labels")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,34 +183,39 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
		viewType   string
 | 
							viewType   string
 | 
				
			||||||
		sortType   = ctx.Query("sort")
 | 
							sortType   = ctx.Query("sort")
 | 
				
			||||||
		filterMode = models.FilterModeAll
 | 
							filterMode = models.FilterModeAll
 | 
				
			||||||
		assigneeID int64
 | 
					 | 
				
			||||||
		posterID   int64
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctxUser.IsOrganization() {
 | 
						if ctxUser.IsOrganization() {
 | 
				
			||||||
		viewType = "all"
 | 
							viewType = "all"
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		viewType = ctx.Query("type")
 | 
							viewType = ctx.Query("type")
 | 
				
			||||||
		types := []string{"assigned", "created_by"}
 | 
							types := []string{"all", "assigned", "created_by"}
 | 
				
			||||||
		if !com.IsSliceContainsStr(types, viewType) {
 | 
							if !com.IsSliceContainsStr(types, viewType) {
 | 
				
			||||||
			viewType = "all"
 | 
								viewType = "all"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch viewType {
 | 
							switch viewType {
 | 
				
			||||||
 | 
							case "all":
 | 
				
			||||||
 | 
								filterMode = models.FilterModeAll
 | 
				
			||||||
		case "assigned":
 | 
							case "assigned":
 | 
				
			||||||
			filterMode = models.FilterModeAssign
 | 
								filterMode = models.FilterModeAssign
 | 
				
			||||||
			assigneeID = ctxUser.ID
 | 
					 | 
				
			||||||
		case "created_by":
 | 
							case "created_by":
 | 
				
			||||||
			filterMode = models.FilterModeCreate
 | 
								filterMode = models.FilterModeCreate
 | 
				
			||||||
			posterID = ctxUser.ID
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page := ctx.QueryInt("page")
 | 
				
			||||||
 | 
						if page <= 1 {
 | 
				
			||||||
 | 
							page = 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repoID := ctx.QueryInt64("repo")
 | 
						repoID := ctx.QueryInt64("repo")
 | 
				
			||||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
						isShowClosed := ctx.Query("state") == "closed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get repositories.
 | 
						// Get repositories.
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	var repos []*models.Repository
 | 
						var repos []*models.Repository
 | 
				
			||||||
 | 
						userRepoIDs := make([]int64, 0, len(repos))
 | 
				
			||||||
	if ctxUser.IsOrganization() {
 | 
						if ctxUser.IsOrganization() {
 | 
				
			||||||
		env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
							env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -230,9 +235,6 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
		repos = ctxUser.Repos
 | 
							repos = ctxUser.Repos
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allCount := 0
 | 
					 | 
				
			||||||
	repoIDs := make([]int64, 0, len(repos))
 | 
					 | 
				
			||||||
	showRepos := make([]*models.Repository, 0, len(repos))
 | 
					 | 
				
			||||||
	for _, repo := range repos {
 | 
						for _, repo := range repos {
 | 
				
			||||||
		if (isPullList && repo.NumPulls == 0) ||
 | 
							if (isPullList && repo.NumPulls == 0) ||
 | 
				
			||||||
			(!isPullList &&
 | 
								(!isPullList &&
 | 
				
			||||||
| 
						 | 
					@ -240,85 +242,129 @@ func Issues(ctx *context.Context) {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		repoIDs = append(repoIDs, repo.ID)
 | 
							userRepoIDs = append(userRepoIDs, repo.ID)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if isPullList {
 | 
					 | 
				
			||||||
			allCount += repo.NumOpenPulls
 | 
					 | 
				
			||||||
			repo.NumOpenIssues = repo.NumOpenPulls
 | 
					 | 
				
			||||||
			repo.NumClosedIssues = repo.NumClosedPulls
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			allCount += repo.NumOpenIssues
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if filterMode != models.FilterModeAll {
 | 
					 | 
				
			||||||
			// Calculate repository issue count with filter mode.
 | 
					 | 
				
			||||||
			numOpen, numClosed := repo.IssueStats(ctxUser.ID, filterMode, isPullList)
 | 
					 | 
				
			||||||
			repo.NumOpenIssues, repo.NumClosedIssues = int(numOpen), int(numClosed)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if repo.ID == repoID ||
 | 
					 | 
				
			||||||
			(isShowClosed && repo.NumClosedIssues > 0) ||
 | 
					 | 
				
			||||||
			(!isShowClosed && repo.NumOpenIssues > 0) {
 | 
					 | 
				
			||||||
			showRepos = append(showRepos, repo)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.Data["Repos"] = showRepos
 | 
					 | 
				
			||||||
	if len(repoIDs) == 0 {
 | 
					 | 
				
			||||||
		repoIDs = []int64{-1}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, repoIDs, filterMode, isPullList)
 | 
						var issues []*models.Issue
 | 
				
			||||||
	issueStats.AllCount = int64(allCount)
 | 
						switch filterMode {
 | 
				
			||||||
 | 
						case models.FilterModeAll:
 | 
				
			||||||
 | 
							// Get all issues from repositories from this user.
 | 
				
			||||||
 | 
							issues, err = models.Issues(&models.IssuesOptions{
 | 
				
			||||||
 | 
								RepoIDs:  userRepoIDs,
 | 
				
			||||||
 | 
								RepoID:   repoID,
 | 
				
			||||||
 | 
								Page:     page,
 | 
				
			||||||
 | 
								IsClosed: util.OptionalBoolOf(isShowClosed),
 | 
				
			||||||
 | 
								IsPull:   util.OptionalBoolOf(isPullList),
 | 
				
			||||||
 | 
								SortType: sortType,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page := ctx.QueryInt("page")
 | 
						case models.FilterModeAssign:
 | 
				
			||||||
	if page <= 1 {
 | 
							// Get all issues assigned to this user.
 | 
				
			||||||
		page = 1
 | 
							issues, err = models.Issues(&models.IssuesOptions{
 | 
				
			||||||
 | 
								RepoID:     repoID,
 | 
				
			||||||
 | 
								AssigneeID: ctxUser.ID,
 | 
				
			||||||
 | 
								Page:       page,
 | 
				
			||||||
 | 
								IsClosed:   util.OptionalBoolOf(isShowClosed),
 | 
				
			||||||
 | 
								IsPull:     util.OptionalBoolOf(isPullList),
 | 
				
			||||||
 | 
								SortType:   sortType,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case models.FilterModeCreate:
 | 
				
			||||||
 | 
							// Get all issues created by this user.
 | 
				
			||||||
 | 
							issues, err = models.Issues(&models.IssuesOptions{
 | 
				
			||||||
 | 
								RepoID:   repoID,
 | 
				
			||||||
 | 
								PosterID: ctxUser.ID,
 | 
				
			||||||
 | 
								Page:     page,
 | 
				
			||||||
 | 
								IsClosed: util.OptionalBoolOf(isShowClosed),
 | 
				
			||||||
 | 
								IsPull:   util.OptionalBoolOf(isPullList),
 | 
				
			||||||
 | 
								SortType: sortType,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						case models.FilterModeMention:
 | 
				
			||||||
 | 
							// Get all issues created by this user.
 | 
				
			||||||
 | 
							issues, err = models.Issues(&models.IssuesOptions{
 | 
				
			||||||
 | 
								RepoID:      repoID,
 | 
				
			||||||
 | 
								MentionedID: ctxUser.ID,
 | 
				
			||||||
 | 
								Page:        page,
 | 
				
			||||||
 | 
								IsClosed:    util.OptionalBoolOf(isShowClosed),
 | 
				
			||||||
 | 
								IsPull:      util.OptionalBoolOf(isPullList),
 | 
				
			||||||
 | 
								SortType:    sortType,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.Handle(500, "Issues", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						showRepos := make([]*models.Repository, 0, len(issues))
 | 
				
			||||||
 | 
						showReposSet := make(map[int64]bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if repoID > 0 {
 | 
				
			||||||
 | 
							repo, err := models.GetRepositoryByID(repoID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", repoID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err = repo.GetOwner(); err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", repoID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Check if user has access to given repository.
 | 
				
			||||||
 | 
							if !repo.IsOwnedBy(ctxUser.ID) && !repo.HasAccess(ctxUser) {
 | 
				
			||||||
 | 
								ctx.Handle(404, "Issues", fmt.Errorf("#%d", repoID))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							showReposSet[repoID] = true
 | 
				
			||||||
 | 
							showRepos = append(showRepos, repo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, issue := range issues {
 | 
				
			||||||
 | 
							// Get Repository data.
 | 
				
			||||||
 | 
							issue.Repo, err = models.GetRepositoryByID(issue.RepoID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issue.RepoID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Get Owner data.
 | 
				
			||||||
 | 
							if err = issue.Repo.GetOwner(); err != nil {
 | 
				
			||||||
 | 
								ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issue.RepoID, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Append repo to list of shown repos
 | 
				
			||||||
 | 
							if filterMode == models.FilterModeAll {
 | 
				
			||||||
 | 
								// Use a map to make sure we don't add the same Repository twice.
 | 
				
			||||||
 | 
								_, ok := showReposSet[issue.RepoID]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									showReposSet[issue.RepoID] = true
 | 
				
			||||||
 | 
									// Append to list of shown Repositories.
 | 
				
			||||||
 | 
									showRepos = append(showRepos, issue.Repo)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, userRepoIDs, filterMode, isPullList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var total int
 | 
						var total int
 | 
				
			||||||
	if !isShowClosed {
 | 
						if !isShowClosed {
 | 
				
			||||||
		total = int(issueStats.OpenCount)
 | 
							total = int(issueStats.OpenCount)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		total = int(issueStats.ClosedCount)
 | 
							total = int(issueStats.ClosedCount)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get issues.
 | 
					 | 
				
			||||||
	issues, err := models.Issues(&models.IssuesOptions{
 | 
					 | 
				
			||||||
		AssigneeID: assigneeID,
 | 
					 | 
				
			||||||
		RepoID:     repoID,
 | 
					 | 
				
			||||||
		PosterID:   posterID,
 | 
					 | 
				
			||||||
		RepoIDs:    repoIDs,
 | 
					 | 
				
			||||||
		Page:       page,
 | 
					 | 
				
			||||||
		IsClosed:   util.OptionalBoolOf(isShowClosed),
 | 
					 | 
				
			||||||
		IsPull:     util.OptionalBoolOf(isPullList),
 | 
					 | 
				
			||||||
		SortType:   sortType,
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		ctx.Handle(500, "Issues", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get posters and repository.
 | 
					 | 
				
			||||||
	for i := range issues {
 | 
					 | 
				
			||||||
		issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err = issues[i].Repo.GetOwner(); err != nil {
 | 
					 | 
				
			||||||
			ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issues[i].ID, err))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.Data["Issues"] = issues
 | 
						ctx.Data["Issues"] = issues
 | 
				
			||||||
 | 
						ctx.Data["Repos"] = showRepos
 | 
				
			||||||
 | 
						ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
 | 
				
			||||||
	ctx.Data["IssueStats"] = issueStats
 | 
						ctx.Data["IssueStats"] = issueStats
 | 
				
			||||||
	ctx.Data["ViewType"] = viewType
 | 
						ctx.Data["ViewType"] = viewType
 | 
				
			||||||
	ctx.Data["SortType"] = sortType
 | 
						ctx.Data["SortType"] = sortType
 | 
				
			||||||
	ctx.Data["RepoID"] = repoID
 | 
						ctx.Data["RepoID"] = repoID
 | 
				
			||||||
	ctx.Data["IsShowClosed"] = isShowClosed
 | 
						ctx.Data["IsShowClosed"] = isShowClosed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if isShowClosed {
 | 
						if isShowClosed {
 | 
				
			||||||
		ctx.Data["State"] = "closed"
 | 
							ctx.Data["State"] = "closed"
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,9 @@
 | 
				
			||||||
		<div class="ui grid">
 | 
							<div class="ui grid">
 | 
				
			||||||
			<div class="four wide column">
 | 
								<div class="four wide column">
 | 
				
			||||||
				<div class="ui secondary vertical filter menu">
 | 
									<div class="ui secondary vertical filter menu">
 | 
				
			||||||
					<a class="{{if eq .ViewType "all"}}ui basic blue button{{end}} item" href="{{.Link}}?repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
 | 
										<a class="{{if eq .ViewType "your_repositories"}}ui basic blue button{{end}} item" href="{{.Link}}?type=your_repositories&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
 | 
				
			||||||
						{{.i18n.Tr "home.issues.in_your_repos"}}
 | 
											{{.i18n.Tr "home.issues.in_your_repos"}}
 | 
				
			||||||
						<strong class="ui right">{{.IssueStats.AllCount}}</strong>
 | 
											<strong class="ui right">{{.IssueStats.YourRepositoriesCount}}</strong>
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
					{{if not .ContextUser.IsOrganization}}
 | 
										{{if not .ContextUser.IsOrganization}}
 | 
				
			||||||
						<a class="{{if eq .ViewType "assigned"}}ui basic blue button{{end}} item" href="{{.Link}}?type=assigned&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
 | 
											<a class="{{if eq .ViewType "assigned"}}ui basic blue button{{end}} item" href="{{.Link}}?type=assigned&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@
 | 
				
			||||||
					<div class="ui divider"></div>
 | 
										<div class="ui divider"></div>
 | 
				
			||||||
					{{range .Repos}}
 | 
										{{range .Repos}}
 | 
				
			||||||
						<a class="{{if eq $.RepoID .ID}}ui basic blue button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}{{if not (eq $.RepoID .ID)}}&repo={{.ID}}{{end}}&sort={{$.SortType}}&state={{$.State}}">
 | 
											<a class="{{if eq $.RepoID .ID}}ui basic blue button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}{{if not (eq $.RepoID .ID)}}&repo={{.ID}}{{end}}&sort={{$.SortType}}&state={{$.State}}">
 | 
				
			||||||
							<span class="text truncate">{{$.ContextUser.Name}}/{{.Name}}</span>
 | 
												<span class="text truncate">{{.FullName}}</span>
 | 
				
			||||||
							<div class="floating ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</div>
 | 
												<div class="floating ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</div>
 | 
				
			||||||
						</a>
 | 
											</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
| 
						 | 
					@ -61,7 +61,7 @@
 | 
				
			||||||
					{{range .Issues}}
 | 
										{{range .Issues}}
 | 
				
			||||||
						{{ $timeStr:= TimeSince .Created $.Lang }}
 | 
											{{ $timeStr:= TimeSince .Created $.Lang }}
 | 
				
			||||||
						<li class="item">
 | 
											<li class="item">
 | 
				
			||||||
							<div class="ui label">{{if not $.RepoID}}{{.Repo.Name}}{{end}}#{{.Index}}</div>
 | 
												<div class="ui label">{{if not $.RepoID}}{{.Repo.FullName}}{{end}}#{{.Index}}</div>
 | 
				
			||||||
							<a class="title has-emoji" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Title}}</a>
 | 
												<a class="title has-emoji" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Title}}</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							{{range .Labels}}
 | 
												{{range .Labels}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue