aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEthan Koenig <etk39@cornell.edu>2017-06-14 23:09:03 -0400
committerKim "BKC" Carlbäcker <kim.carlbacker@gmail.com>2017-06-15 05:09:03 +0200
commit8fcda0442e60209d7e6783c95d96f20ff04dbdd6 (patch)
tree8b47fcaab6003453ec319fc4960d959a2d06e6e9
parentbf48c8ebdd3975d1090115a9106069796c67a6da (diff)
downloadgitea-8fcda0442e60209d7e6783c95d96f20ff04dbdd6.tar.gz
gitea-8fcda0442e60209d7e6783c95d96f20ff04dbdd6.zip
Fix search by issue type (#1914)
* Fix search by issue type
-rw-r--r--integrations/issue_test.go50
-rw-r--r--models/issue.go52
-rw-r--r--models/unit_tests.go40
-rw-r--r--routers/repo/issue.go12
-rw-r--r--templates/repo/issue/list.tmpl26
5 files changed, 121 insertions, 59 deletions
diff --git a/integrations/issue_test.go b/integrations/issue_test.go
index 3b486dc505..f94f11a863 100644
--- a/integrations/issue_test.go
+++ b/integrations/issue_test.go
@@ -6,11 +6,30 @@ package integrations
import (
"net/http"
+ "strconv"
+ "strings"
"testing"
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/setting"
+
+ "github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
)
+func getIssuesSelection(htmlDoc *HtmlDoc) *goquery.Selection {
+ return htmlDoc.doc.Find(".issue.list").Find("li").Find(".title")
+}
+
+func getIssue(t *testing.T, repoID int64, issueSelection *goquery.Selection) *models.Issue {
+ href, exists := issueSelection.Attr("href")
+ assert.True(t, exists)
+ indexStr := href[strings.LastIndexByte(href, '/')+1:]
+ index, err := strconv.Atoi(indexStr)
+ assert.NoError(t, err, "Invalid issue href: %s", href)
+ return models.AssertExistsAndLoadBean(t, &models.Issue{RepoID: repoID, Index: int64(index)}).(*models.Issue)
+}
+
func TestNoLoginViewIssues(t *testing.T) {
prepareTestEnv(t)
@@ -19,6 +38,37 @@ func TestNoLoginViewIssues(t *testing.T) {
assert.EqualValues(t, http.StatusOK, resp.HeaderCode)
}
+func TestNoLoginViewIssuesSortByType(t *testing.T) {
+ prepareTestEnv(t)
+
+ user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
+ repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
+ repo.Owner = models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
+
+ session := loginUser(t, user.Name, "password")
+ req := NewRequest(t, "GET", repo.RelLink()+"/issues?type=created_by")
+ resp := session.MakeRequest(t, req)
+ assert.EqualValues(t, http.StatusOK, resp.HeaderCode)
+
+ htmlDoc, err := NewHtmlParser(resp.Body)
+ assert.NoError(t, err)
+ issuesSelection := getIssuesSelection(htmlDoc)
+ expectedNumIssues := models.GetCount(t,
+ &models.Issue{RepoID: repo.ID, PosterID: user.ID},
+ models.Cond("is_closed=?", false),
+ models.Cond("is_pull=?", false),
+ )
+ if expectedNumIssues > setting.UI.IssuePagingNum {
+ expectedNumIssues = setting.UI.IssuePagingNum
+ }
+ assert.EqualValues(t, expectedNumIssues, issuesSelection.Length())
+
+ issuesSelection.Each(func(_ int, selection *goquery.Selection) {
+ issue := getIssue(t, repo.ID, selection)
+ assert.EqualValues(t, user.ID, issue.PosterID)
+ })
+}
+
func TestNoLoginViewIssue(t *testing.T) {
prepareTestEnv(t)
diff --git a/models/issue.go b/models/issue.go
index 8340595fca..d4d0a5a2ff 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -1223,7 +1223,6 @@ func parseCountResult(results []map[string][]byte) int64 {
// IssueStatsOptions contains parameters accepted by GetIssueStats.
type IssueStatsOptions struct {
- FilterMode int
RepoID int64
Labels string
MilestoneID int64
@@ -1241,7 +1240,7 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
countSession := func(opts *IssueStatsOptions) *xorm.Session {
sess := x.
Where("issue.repo_id = ?", opts.RepoID).
- And("is_pull = ?", opts.IsPull)
+ And("issue.is_pull = ?", opts.IsPull)
if len(opts.IssueIDs) > 0 {
sess.In("issue.id", opts.IssueIDs)
@@ -1252,8 +1251,8 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
if err != nil {
log.Warn("Malformed Labels argument: %s", opts.Labels)
} else if len(labelIDs) > 0 {
- sess.Join("INNER", "issue_label", "issue.id = issue_id").
- In("label_id", labelIDs)
+ sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id").
+ In("issue_label.label_id", labelIDs)
}
}
@@ -1262,11 +1261,11 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
}
if opts.AssigneeID > 0 {
- sess.And("assignee_id = ?", opts.AssigneeID)
+ sess.And("issue.assignee_id = ?", opts.AssigneeID)
}
if opts.PosterID > 0 {
- sess.And("poster_id = ?", opts.PosterID)
+ sess.And("issue.poster_id = ?", opts.PosterID)
}
if opts.MentionedID > 0 {
@@ -1279,40 +1278,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
}
var err error
- switch opts.FilterMode {
- case FilterModeAll, FilterModeAssign:
- stats.OpenCount, err = countSession(opts).
- And("is_closed = ?", false).
- 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.OpenCount, err = countSession(opts).
+ And("issue.is_closed = ?", false).
+ Count(new(Issue))
+ if err != nil {
+ return stats, err
}
+ stats.ClosedCount, err = countSession(opts).
+ And("issue.is_closed = ?", true).
+ Count(new(Issue))
return stats, err
}
diff --git a/models/unit_tests.go b/models/unit_tests.go
index a3459e49f7..16eb09968c 100644
--- a/models/unit_tests.go
+++ b/models/unit_tests.go
@@ -37,13 +37,31 @@ func PrepareTestDatabase() error {
return LoadFixtures()
}
+type testCond struct {
+ query interface{}
+ args []interface{}
+}
+
+// Cond create a condition with arguments for a test
+func Cond(query interface{}, args ...interface{}) interface{} {
+ return &testCond{query: query, args: args}
+}
+
+func whereConditions(sess *xorm.Session, conditions []interface{}) {
+ for _, condition := range conditions {
+ switch cond := condition.(type) {
+ case *testCond:
+ sess.Where(cond.query, cond.args...)
+ default:
+ sess.Where(cond)
+ }
+ }
+}
+
func loadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error) {
sess := x.NewSession()
defer sess.Close()
-
- for _, cond := range conditions {
- sess = sess.Where(cond)
- }
+ whereConditions(sess, conditions)
return sess.Get(bean)
}
@@ -65,6 +83,16 @@ func AssertExistsAndLoadBean(t *testing.T, bean interface{}, conditions ...inter
return bean
}
+// GetCount get the count of a bean
+func GetCount(t *testing.T, bean interface{}, conditions ...interface{}) int {
+ sess := x.NewSession()
+ defer sess.Close()
+ whereConditions(sess, conditions)
+ count, err := sess.Count(bean)
+ assert.NoError(t, err)
+ return int(count)
+}
+
// AssertNotExistsBean assert that a bean does not exist in the test database
func AssertNotExistsBean(t *testing.T, bean interface{}, conditions ...interface{}) {
exists, err := loadBeanIfExists(bean, conditions...)
@@ -80,7 +108,5 @@ func AssertSuccessfulInsert(t *testing.T, beans ...interface{}) {
// AssertCount assert the count of a bean
func AssertCount(t *testing.T, bean interface{}, expected interface{}) {
- actual, err := x.Count(bean)
- assert.NoError(t, err)
- assert.EqualValues(t, expected, actual)
+ assert.EqualValues(t, expected, GetCount(t, bean))
}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index c54cd28439..b94eddc4ef 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -120,6 +120,15 @@ func Issues(ctx *context.Context) {
forceEmpty bool
)
+ if ctx.IsSigned {
+ switch viewType {
+ case "created_by":
+ posterID = ctx.User.ID
+ case "mentioned":
+ mentionedID = ctx.User.ID
+ }
+ }
+
repo := ctx.Repo.Repository
selectLabels := ctx.Query("labels")
milestoneID := ctx.QueryInt64("milestone")
@@ -150,11 +159,12 @@ func Issues(ctx *context.Context) {
MilestoneID: milestoneID,
AssigneeID: assigneeID,
MentionedID: mentionedID,
+ PosterID: posterID,
IsPull: isPullList,
IssueIDs: issueIDs,
})
if err != nil {
- ctx.Error(500, "GetSearchIssueStats")
+ ctx.Handle(500, "GetIssueStats", err)
return
}
}
diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl
index 863ae6a74d..8de52fb23f 100644
--- a/templates/repo/issue/list.tmpl
+++ b/templates/repo/issue/list.tmpl
@@ -68,19 +68,21 @@
</div>
</div>
- <!-- Type -->
- <div class="ui dropdown type jump item">
- <span class="text">
- {{.i18n.Tr "repo.issues.filter_type"}}
- <i class="dropdown icon"></i>
- </span>
- <div class="menu">
- <a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.all_issues"}}</a>
- <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
- <a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
- <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+ {{if .IsSigned}}
+ <!-- Type -->
+ <div class="ui dropdown type jump item">
+ <span class="text">
+ {{.i18n.Tr "repo.issues.filter_type"}}
+ <i class="dropdown icon"></i>
+ </span>
+ <div class="menu">
+ <a class="{{if eq .ViewType "all"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.all_issues"}}</a>
+ <a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{.SignedUser.ID}}">{{.i18n.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
+ <a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.created_by_you"}}</a>
+ <a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_type.mentioning_you"}}</a>
+ </div>
</div>
- </div>
+ {{end}}
<!-- Sort -->
<div class="ui dropdown type jump item">