From cea8842605ee578041c39ded671db937b15bce71 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 6 Apr 2022 22:45:07 +0800 Subject: [PATCH] add some tests and fix missed api/v1 in sidebar.tmpl --- integrations/issue_test.go | 202 ++++++++++++++++++ integrations/org_test.go | 29 +++ integrations/repo_topic_test.go | 46 ++++ integrations/user_test.go | 26 +++ routers/web/repo/issue.go | 36 ++++ routers/web/web.go | 2 + .../repo/issue/view_content/sidebar.tmpl | 2 +- web_src/js/features/repo-issue.js | 2 +- 8 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 integrations/repo_topic_test.go diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 6a9b48e5a41d..08b60523ddf6 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -7,6 +7,7 @@ package integrations import ( "fmt" "net/http" + "net/url" "path" "strconv" "strings" @@ -20,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/indexer/issues" "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "github.com/PuerkitoBio/goquery" @@ -347,3 +349,203 @@ func TestIssueRedirect(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusSeeOther) assert.Equal(t, "/"+path.Join("org26", "repo_external_tracker_alpha", "pulls", "1"), test.RedirectURL(resp)) } + +func TestSearchIssues(t *testing.T) { + defer prepareTestEnv(t)() + + session := loginUser(t, "user2") + + link, _ := url.Parse("/issues/search") + req := NewRequest(t, "GET", link.String()) + resp := session.MakeRequest(t, req, http.StatusOK) + var apiIssues []*api.Issue + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 + before := time.Unix(999307200, 0).Format(time.RFC3339) + query := url.Values{} + query.Add("since", since) + query.Add("before", before) + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 8) + query.Del("since") + query.Del("before") + + query.Add("state", "closed") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + query.Set("state", "all") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count")) + assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit + + query.Add("limit", "20") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 15) + + query = url.Values{"assigned": {"true"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + query = url.Values{"milestones": {"milestone1"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + query = url.Values{"owner": {"user2"}} // user + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 6) + + query = url.Values{"owner": {"user3"}} // organization + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 3) + + query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) +} + +func TestSearchIssuesWithLabels(t *testing.T) { + defer prepareTestEnv(t)() + + session := loginUser(t, "user1") + + link, _ := url.Parse("/api/v1/repos/issues/search") + req := NewRequest(t, "GET", link.String()) + resp := session.MakeRequest(t, req, http.StatusOK) + var apiIssues []*api.Issue + DecodeJSON(t, resp, &apiIssues) + + assert.Len(t, apiIssues, 10) + + query := url.Values{} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + query.Add("labels", "label1") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // multiple labels + query.Set("labels", "label1,label2") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // an org label + query.Set("labels", "orglabel4") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + // org and repo label + query.Set("labels", "label2,orglabel4") + query.Add("state", "all") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // org and repo label which share the same issue + query.Set("labels", "label1,orglabel4") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) +} + +func TestGetIssueInfo(t *testing.T) { + defer prepareTestEnv(t)() + + issueBefore := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + assert.NoError(t, issueBefore.LoadAttributes()) + assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) + assert.Equal(t, api.StateOpen, issueBefore.State()) + + session := loginUser(t, owner.Name) + + urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repoBefore.Name, issueBefore.Index) + req := NewRequest(t, "Get", urlStr) + resp := session.MakeRequest(t, req, http.StatusCreated) + var apiIssue api.Issue + DecodeJSON(t, resp, &apiIssue) + + assert.EqualValues(t, issueBefore.ID, apiIssue.ID) +} + +func TestUpdateIssueDeadline(t *testing.T) { + defer prepareTestEnv(t)() + + issueBefore := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + assert.NoError(t, issueBefore.LoadAttributes()) + assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) + assert.Equal(t, api.StateOpen, issueBefore.State()) + + session := loginUser(t, owner.Name) + + urlStr := fmt.Sprintf("/%s/%s/issues/%d/deadline", owner.Name, repoBefore.Name, issueBefore.Index) + req := NewRequestWithJSON(t, "Post", urlStr, map[string]string{ + "due_date": "2022-04-06", + }) + resp := session.MakeRequest(t, req, http.StatusCreated) + var apiIssue api.IssueDeadline + DecodeJSON(t, resp, &apiIssue) + + assert.EqualValues(t, "2022-04-06", apiIssue.Deadline.Format("2006-01-02")) +} diff --git a/integrations/org_test.go b/integrations/org_test.go index 794475a9245d..cb44c9aa5dd7 100644 --- a/integrations/org_test.go +++ b/integrations/org_test.go @@ -10,6 +10,8 @@ import ( "strings" "testing" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -173,3 +175,30 @@ func TestOrgRestrictedUser(t *testing.T) { req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s", orgName, repoName)) restrictedSession.MakeRequest(t, req, http.StatusOK) } + +func TestTeamSearch(t *testing.T) { + defer prepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + + var results TeamSearchResults + + session := loginUser(t, user.Name) + csrf := GetCSRF(t, session, "/"+org.Name) + req := NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "_team") + req.Header.Add("X-Csrf-Token", csrf) + resp := session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &results) + assert.NotEmpty(t, results.Data) + assert.Len(t, results.Data, 1) + assert.Equal(t, "test_team", results.Data[0].Name) + + // no access if not organization member + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + session = loginUser(t, user5.Name) + csrf = GetCSRF(t, session, "/"+org.Name) + req = NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "team") + req.Header.Add("X-Csrf-Token", csrf) + session.MakeRequest(t, req, http.StatusForbidden) +} diff --git a/integrations/repo_topic_test.go b/integrations/repo_topic_test.go new file mode 100644 index 000000000000..146f90e710f2 --- /dev/null +++ b/integrations/repo_topic_test.go @@ -0,0 +1,46 @@ +// Copyright 2022 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 integrations + +import ( + "net/http" + "net/url" + "testing" + + api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" +) + +func TestTopicSearch(t *testing.T) { + defer prepareTestEnv(t)() + searchURL, _ := url.Parse("/explore/topics/search") + var topics struct { + TopicNames []*api.TopicResponse `json:"topics"` + } + + query := url.Values{"page": []string{"1"}, "limit": []string{"4"}} + + searchURL.RawQuery = query.Encode() + res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + assert.Len(t, topics.TopicNames, 4) + assert.EqualValues(t, "6", res.Header().Get("x-total-count")) + + query.Add("q", "topic") + searchURL.RawQuery = query.Encode() + res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + assert.Len(t, topics.TopicNames, 2) + + query.Set("q", "database") + searchURL.RawQuery = query.Encode() + res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + if assert.Len(t, topics.TopicNames, 1) { + assert.EqualValues(t, 2, topics.TopicNames[0].ID) + assert.EqualValues(t, "database", topics.TopicNames[0].Name) + assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount) + } +} diff --git a/integrations/user_test.go b/integrations/user_test.go index e8fbccd51e8a..d0523d8b3a98 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -8,8 +8,11 @@ import ( "net/http" "testing" + "code.gitea.io/gitea/models" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation/i18n" @@ -222,3 +225,26 @@ func testExportUserGPGKeys(t *testing.T, user, expected string) { // t.Log(resp.Body.String()) assert.Equal(t, expected, resp.Body.String()) } + +func TestListStopWatches(t *testing.T) { + defer prepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + + session := loginUser(t, owner.Name) + req := NewRequestf(t, "GET", "/user/stopwatches") + resp := session.MakeRequest(t, req, http.StatusOK) + var apiWatches []*api.StopWatch + DecodeJSON(t, resp, &apiWatches) + stopwatch := unittest.AssertExistsAndLoadBean(t, &models.Stopwatch{UserID: owner.ID}).(*models.Stopwatch) + issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: stopwatch.IssueID}).(*models.Issue) + if assert.Len(t, apiWatches, 1) { + assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix()) + assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex) + assert.EqualValues(t, issue.Title, apiWatches[0].IssueTitle) + assert.EqualValues(t, repo.Name, apiWatches[0].RepoName) + assert.EqualValues(t, repo.OwnerName, apiWatches[0].RepoOwnerName) + assert.Greater(t, int64(apiWatches[0].Seconds), int64(0)) + } +} diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 36733a26f091..1fd60812f935 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -16,6 +16,7 @@ import ( "path" "strconv" "strings" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -36,6 +37,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates/vars" + "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -1870,6 +1872,40 @@ func UpdateIssueContent(ctx *context.Context) { }) } +// UpdateIssueDeadline updates an issue deadline +func UpdateIssueDeadline(ctx *context.Context) { + form := web.GetForm(ctx).(*api.EditDeadlineOption) + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.NotFound("GetIssueByIndex", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err.Error()) + } + return + } + + if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) { + ctx.Error(http.StatusForbidden, "", "Not repo writer") + return + } + + var deadlineUnix timeutil.TimeStamp + var deadline time.Time + if form.Deadline != nil && !form.Deadline.IsZero() { + deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(), + 23, 59, 59, 0, time.Local) + deadlineUnix = timeutil.TimeStamp(deadline.Unix()) + } + + if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error()) + return + } + + ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline}) +} + // UpdateIssueMilestone change issue's milestone func UpdateIssueMilestone(ctx *context.Context) { issues := getActionIssues(ctx) diff --git a/routers/web/web.go b/routers/web/web.go index 0454b2896b32..9a2e96aeec3e 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/public" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" @@ -829,6 +830,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/info", repo.GetIssueInfo) m.Post("/title", repo.UpdateIssueTitle) m.Post("/content", repo.UpdateIssueContent) + m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) m.Post("/watch", repo.IssueWatch) m.Post("/ref", repo.UpdateIssueRef) m.Group("/dependency", func() { diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index aed155fdbfb4..e673add812a8 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -429,7 +429,7 @@ {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}}