From 7e0654bd9e4f90fc156884afd88cb82ad8df86a8 Mon Sep 17 00:00:00 2001
From: Ethan Koenig <etk39@cornell.edu>
Date: Wed, 2 Aug 2017 22:09:16 -0700
Subject: Fix counts on issues dashboard (#2215)

* Fix counts on issues dashboard

* setupSess -> setupSession

* Unit test

* Load repo owners for issues
---
 routers/api/v1/repo/issue.go |  1 +
 routers/repo/issue.go        |  1 +
 routers/user/home.go         | 98 ++++++++++++++++++--------------------------
 routers/user/home_test.go    | 33 +++++++++++++++
 routers/user/main_test.go    | 33 +++++++++++++++
 5 files changed, 109 insertions(+), 57 deletions(-)
 create mode 100644 routers/user/home_test.go
 create mode 100644 routers/user/main_test.go

(limited to 'routers')

diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 253bdb43d2..9f51022f35 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -31,6 +31,7 @@ func ListIssues(ctx *context.APIContext) {
 	issues, err := models.Issues(&models.IssuesOptions{
 		RepoID:   ctx.Repo.Repository.ID,
 		Page:     ctx.QueryInt("page"),
+		PageSize: setting.UI.IssuePagingNum,
 		IsClosed: isClosed,
 	})
 	if err != nil {
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 473e829713..e4ed10d980 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -193,6 +193,7 @@ func Issues(ctx *context.Context) {
 			MentionedID: mentionedID,
 			MilestoneID: milestoneID,
 			Page:        pager.Current(),
+			PageSize:    setting.UI.IssuePagingNum,
 			IsClosed:    util.OptionalBoolOf(isShowClosed),
 			IsPull:      util.OptionalBoolOf(isPullList),
 			Labels:      selectLabels,
diff --git a/routers/user/home.go b/routers/user/home.go
index 7128890690..b2096bc2ce 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -270,94 +270,77 @@ func Issues(ctx *context.Context) {
 		userRepoIDs = []int64{-1}
 	}
 
-	var issues []*models.Issue
+	opts := &models.IssuesOptions{
+		RepoID:   repoID,
+		IsClosed: util.OptionalBoolOf(isShowClosed),
+		IsPull:   util.OptionalBoolOf(isPullList),
+		SortType: sortType,
+	}
+
 	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,
-		})
-
+		opts.RepoIDs = userRepoIDs
 	case models.FilterModeAssign:
-		// Get all issues assigned to this user.
-		issues, err = models.Issues(&models.IssuesOptions{
-			RepoID:     repoID,
-			AssigneeID: ctxUser.ID,
-			Page:       page,
-			IsClosed:   util.OptionalBoolOf(isShowClosed),
-			IsPull:     util.OptionalBoolOf(isPullList),
-			SortType:   sortType,
-		})
-
+		opts.AssigneeID = ctxUser.ID
 	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,
-		})
+		opts.PosterID = ctxUser.ID
 	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,
-		})
+		opts.MentionedID = ctxUser.ID
 	}
 
+	counts, err := models.CountIssuesByRepo(opts)
 	if err != nil {
-		ctx.Handle(500, "Issues", err)
+		ctx.Handle(500, "CountIssuesByRepo", err)
 		return
 	}
 
-	showRepos, err := models.IssueList(issues).LoadRepositories()
+	opts.Page = page
+	opts.PageSize = setting.UI.IssuePagingNum
+	issues, err := models.Issues(opts)
 	if err != nil {
-		ctx.Handle(500, "LoadRepositories", fmt.Errorf("%v", err))
+		ctx.Handle(500, "Issues", err)
 		return
 	}
 
-	if repoID > 0 {
-		var theRepo *models.Repository
-		for _, repo := range showRepos {
-			if repo.ID == repoID {
-				theRepo = repo
-				break
-			}
+	showReposMap := make(map[int64]*models.Repository, len(counts))
+	for repoID := range counts {
+		repo, err := models.GetRepositoryByID(repoID)
+		if err != nil {
+			ctx.Handle(500, "GetRepositoryByID", err)
+			return
 		}
+		showReposMap[repoID] = repo
+	}
 
-		if theRepo == nil {
-			theRepo, err = models.GetRepositoryByID(repoID)
+	if repoID > 0 {
+		if _, ok := showReposMap[repoID]; !ok {
+			repo, err := models.GetRepositoryByID(repoID)
 			if err != nil {
-				ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", repoID, err))
+				ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err))
 				return
 			}
-			showRepos = append(showRepos, theRepo)
+			showReposMap[repoID] = repo
 		}
 
+		repo := showReposMap[repoID]
+
 		// Check if user has access to given repository.
-		if !theRepo.IsOwnedBy(ctxUser.ID) && !theRepo.HasAccess(ctxUser) {
-			ctx.Handle(404, "Issues", fmt.Errorf("#%d", repoID))
+		if !repo.IsOwnedBy(ctxUser.ID) && !repo.HasAccess(ctxUser) {
+			ctx.Status(404)
 			return
 		}
 	}
 
-	err = models.RepositoryList(showRepos).LoadAttributes()
-	if err != nil {
+	showRepos := models.RepositoryListOfMap(showReposMap)
+	if err = showRepos.LoadAttributes(); err != nil {
 		ctx.Handle(500, "LoadAttributes", fmt.Errorf("%v", err))
 		return
 	}
 
+	for _, issue := range issues {
+		issue.Repo = showReposMap[issue.RepoID]
+	}
+
 	issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, userRepoIDs, filterMode, isPullList)
 
 	var total int
@@ -369,6 +352,7 @@ func Issues(ctx *context.Context) {
 
 	ctx.Data["Issues"] = issues
 	ctx.Data["Repos"] = showRepos
+	ctx.Data["Counts"] = counts
 	ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
 	ctx.Data["IssueStats"] = issueStats
 	ctx.Data["ViewType"] = viewType
diff --git a/routers/user/home_test.go b/routers/user/home_test.go
new file mode 100644
index 0000000000..beca936174
--- /dev/null
+++ b/routers/user/home_test.go
@@ -0,0 +1,33 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+	"net/http"
+	"testing"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/test"
+
+	"code.gitea.io/gitea/modules/setting"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIssues(t *testing.T) {
+	setting.UI.IssuePagingNum = 1
+	assert.NoError(t, models.LoadFixtures())
+
+	ctx := test.MockContext(t)
+	ctx.User = models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
+	ctx.SetParams(":type", "issues")
+	ctx.Req.Form.Set("state", "closed")
+	Issues(ctx)
+	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
+
+	assert.EqualValues(t, map[int64]int64{1: 1, 2: 1}, ctx.Data["Counts"])
+	assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
+	assert.Len(t, ctx.Data["Issues"], 1)
+	assert.Len(t, ctx.Data["Repos"], 2)
+}
diff --git a/routers/user/main_test.go b/routers/user/main_test.go
new file mode 100644
index 0000000000..83c0c65474
--- /dev/null
+++ b/routers/user/main_test.go
@@ -0,0 +1,33 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/modules/setting"
+
+	_ "github.com/mattn/go-sqlite3" // for the test engine
+)
+
+func TestMain(m *testing.M) {
+	if err := models.CreateTestEngine("../../models/fixtures/"); err != nil {
+		fmt.Printf("Error creating test engine: %v\n", err)
+		os.Exit(1)
+	}
+
+	setting.AppURL = "https://try.gitea.io/"
+	setting.RunUser = "runuser"
+	setting.SSH.Port = 3000
+	setting.SSH.Domain = "try.gitea.io"
+	setting.RepoRootPath = filepath.Join(os.TempDir(), "repos")
+	setting.AppDataPath = filepath.Join(os.TempDir(), "appdata")
+
+	os.Exit(m.Run())
+}
-- 
cgit v1.2.3