mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	[API] ListReleases add filter for draft and pre-releases (#16175)
* invent ctx.QueryOptionalBool * [API] ListReleases add draft and pre-release filter * Add X-Total-Count header * Add a release to fixtures * Add TEST for API ListReleases
This commit is contained in:
		@@ -7,6 +7,7 @@ package integrations
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -16,6 +17,58 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIListReleases(t *testing.T) {
 | 
				
			||||||
 | 
						defer prepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
				
			||||||
 | 
						user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
 | 
				
			||||||
 | 
						session := loginUser(t, user2.LowerName)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
 | 
				
			||||||
 | 
						link.RawQuery = url.Values{"token": {token}}.Encode()
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
 | 
				
			||||||
 | 
						var apiReleases []*api.Release
 | 
				
			||||||
 | 
						DecodeJSON(t, resp, &apiReleases)
 | 
				
			||||||
 | 
						if assert.Len(t, apiReleases, 3) {
 | 
				
			||||||
 | 
							for _, release := range apiReleases {
 | 
				
			||||||
 | 
								switch release.ID {
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									assert.False(t, release.IsDraft)
 | 
				
			||||||
 | 
									assert.False(t, release.IsPrerelease)
 | 
				
			||||||
 | 
								case 4:
 | 
				
			||||||
 | 
									assert.True(t, release.IsDraft)
 | 
				
			||||||
 | 
									assert.False(t, release.IsPrerelease)
 | 
				
			||||||
 | 
								case 5:
 | 
				
			||||||
 | 
									assert.False(t, release.IsDraft)
 | 
				
			||||||
 | 
									assert.True(t, release.IsPrerelease)
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									assert.NoError(t, fmt.Errorf("unexpected release: %v", release))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// test filter
 | 
				
			||||||
 | 
						testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
 | 
				
			||||||
 | 
							link.RawQuery = query.Encode()
 | 
				
			||||||
 | 
							if auth {
 | 
				
			||||||
 | 
								query.Set("token", token)
 | 
				
			||||||
 | 
								resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							DecodeJSON(t, resp, &apiReleases)
 | 
				
			||||||
 | 
							assert.Len(t, apiReleases, expectedLength, msgAndArgs)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testFilterByLen(false, url.Values{"draft": {"true"}}, 0, "anon should not see drafts")
 | 
				
			||||||
 | 
						testFilterByLen(true, url.Values{"draft": {"true"}}, 1, "repo owner should see drafts")
 | 
				
			||||||
 | 
						testFilterByLen(true, url.Values{"draft": {"false"}}, 2, "exclude drafts")
 | 
				
			||||||
 | 
						testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
 | 
				
			||||||
 | 
						testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
 | 
				
			||||||
 | 
						testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *models.User, repo *models.Repository, name, target, title, desc string) *api.Release {
 | 
					func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *models.User, repo *models.Repository, name, target, title, desc string) *api.Release {
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
 | 
				
			||||||
		owner.Name, repo.Name, token)
 | 
							owner.Name, repo.Name, token)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -223,7 +223,7 @@ func TestAPIViewRepo(t *testing.T) {
 | 
				
			|||||||
	DecodeJSON(t, resp, &repo)
 | 
						DecodeJSON(t, resp, &repo)
 | 
				
			||||||
	assert.EqualValues(t, 1, repo.ID)
 | 
						assert.EqualValues(t, 1, repo.ID)
 | 
				
			||||||
	assert.EqualValues(t, "repo1", repo.Name)
 | 
						assert.EqualValues(t, "repo1", repo.Name)
 | 
				
			||||||
	assert.EqualValues(t, 2, repo.Releases)
 | 
						assert.EqualValues(t, 3, repo.Releases)
 | 
				
			||||||
	assert.EqualValues(t, 1, repo.OpenIssues)
 | 
						assert.EqualValues(t, 1, repo.OpenIssues)
 | 
				
			||||||
	assert.EqualValues(t, 3, repo.OpenPulls)
 | 
						assert.EqualValues(t, 3, repo.OpenPulls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,7 @@ func TestCreateRelease(t *testing.T) {
 | 
				
			|||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
 | 
						createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 3)
 | 
						checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 4)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateReleasePreRelease(t *testing.T) {
 | 
					func TestCreateReleasePreRelease(t *testing.T) {
 | 
				
			||||||
@@ -94,7 +94,7 @@ func TestCreateReleasePreRelease(t *testing.T) {
 | 
				
			|||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
 | 
						createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 3)
 | 
						checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 4)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateReleaseDraft(t *testing.T) {
 | 
					func TestCreateReleaseDraft(t *testing.T) {
 | 
				
			||||||
@@ -103,7 +103,7 @@ func TestCreateReleaseDraft(t *testing.T) {
 | 
				
			|||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
 | 
						createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 3)
 | 
						checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 4)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateReleasePaging(t *testing.T) {
 | 
					func TestCreateReleasePaging(t *testing.T) {
 | 
				
			||||||
@@ -142,7 +142,7 @@ func TestViewReleaseListNoLogin(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
						htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
				
			||||||
	releases := htmlDoc.Find("#release-list li.ui.grid")
 | 
						releases := htmlDoc.Find("#release-list li.ui.grid")
 | 
				
			||||||
	assert.Equal(t, 1, releases.Length())
 | 
						assert.Equal(t, 2, releases.Length())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	links := make([]string, 0, 5)
 | 
						links := make([]string, 0, 5)
 | 
				
			||||||
	releases.Each(func(i int, s *goquery.Selection) {
 | 
						releases.Each(func(i int, s *goquery.Selection) {
 | 
				
			||||||
@@ -153,7 +153,7 @@ func TestViewReleaseListNoLogin(t *testing.T) {
 | 
				
			|||||||
		links = append(links, link)
 | 
							links = append(links, link)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, []string{"/user2/repo1/releases/tag/v1.1"}, links)
 | 
						assert.EqualValues(t, []string{"/user2/repo1/releases/tag/v1.0", "/user2/repo1/releases/tag/v1.1"}, links)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestViewReleaseListLogin(t *testing.T) {
 | 
					func TestViewReleaseListLogin(t *testing.T) {
 | 
				
			||||||
@@ -169,7 +169,7 @@ func TestViewReleaseListLogin(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
						htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
				
			||||||
	releases := htmlDoc.Find("#release-list li.ui.grid")
 | 
						releases := htmlDoc.Find("#release-list li.ui.grid")
 | 
				
			||||||
	assert.Equal(t, 2, releases.Length())
 | 
						assert.Equal(t, 3, releases.Length())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	links := make([]string, 0, 5)
 | 
						links := make([]string, 0, 5)
 | 
				
			||||||
	releases.Each(func(i int, s *goquery.Selection) {
 | 
						releases.Each(func(i int, s *goquery.Selection) {
 | 
				
			||||||
@@ -180,8 +180,11 @@ func TestViewReleaseListLogin(t *testing.T) {
 | 
				
			|||||||
		links = append(links, link)
 | 
							links = append(links, link)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, []string{"/user2/repo1/releases/tag/draft-release",
 | 
						assert.EqualValues(t, []string{
 | 
				
			||||||
		"/user2/repo1/releases/tag/v1.1"}, links)
 | 
							"/user2/repo1/releases/tag/draft-release",
 | 
				
			||||||
 | 
							"/user2/repo1/releases/tag/v1.0",
 | 
				
			||||||
 | 
							"/user2/repo1/releases/tag/v1.1",
 | 
				
			||||||
 | 
						}, links)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestViewTagsList(t *testing.T) {
 | 
					func TestViewTagsList(t *testing.T) {
 | 
				
			||||||
@@ -197,12 +200,12 @@ func TestViewTagsList(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
						htmlDoc := NewHTMLParser(t, rsp.Body)
 | 
				
			||||||
	tags := htmlDoc.Find(".tag-list tr")
 | 
						tags := htmlDoc.Find(".tag-list tr")
 | 
				
			||||||
	assert.Equal(t, 2, tags.Length())
 | 
						assert.Equal(t, 3, tags.Length())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tagNames := make([]string, 0, 5)
 | 
						tagNames := make([]string, 0, 5)
 | 
				
			||||||
	tags.Each(func(i int, s *goquery.Selection) {
 | 
						tags.Each(func(i int, s *goquery.Selection) {
 | 
				
			||||||
		tagNames = append(tagNames, s.Find(".tag a.df.ac").Text())
 | 
							tagNames = append(tagNames, s.Find(".tag a.df.ac").Text())
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.EqualValues(t, []string{"delete-tag", "v1.1"}, tagNames)
 | 
						assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
-
 | 
					- id: 1
 | 
				
			||||||
  id: 1
 | 
					 | 
				
			||||||
  repo_id: 1
 | 
					  repo_id: 1
 | 
				
			||||||
  publisher_id: 2
 | 
					  publisher_id: 2
 | 
				
			||||||
  tag_name: "v1.1"
 | 
					  tag_name: "v1.1"
 | 
				
			||||||
@@ -13,8 +12,7 @@
 | 
				
			|||||||
  is_tag: false
 | 
					  is_tag: false
 | 
				
			||||||
  created_unix: 946684800
 | 
					  created_unix: 946684800
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-
 | 
					- id: 2
 | 
				
			||||||
  id: 2
 | 
					 | 
				
			||||||
  repo_id: 40
 | 
					  repo_id: 40
 | 
				
			||||||
  publisher_id: 2
 | 
					  publisher_id: 2
 | 
				
			||||||
  tag_name: "v1.1"
 | 
					  tag_name: "v1.1"
 | 
				
			||||||
@@ -28,8 +26,7 @@
 | 
				
			|||||||
  is_tag: false
 | 
					  is_tag: false
 | 
				
			||||||
  created_unix: 946684800
 | 
					  created_unix: 946684800
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-
 | 
					- id: 3
 | 
				
			||||||
  id: 3
 | 
					 | 
				
			||||||
  repo_id: 1
 | 
					  repo_id: 1
 | 
				
			||||||
  publisher_id: 2
 | 
					  publisher_id: 2
 | 
				
			||||||
  tag_name: "delete-tag"
 | 
					  tag_name: "delete-tag"
 | 
				
			||||||
@@ -43,8 +40,7 @@
 | 
				
			|||||||
  is_tag: true
 | 
					  is_tag: true
 | 
				
			||||||
  created_unix: 946684800
 | 
					  created_unix: 946684800
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-
 | 
					- id: 4
 | 
				
			||||||
  id: 4
 | 
					 | 
				
			||||||
  repo_id: 1
 | 
					  repo_id: 1
 | 
				
			||||||
  publisher_id: 2
 | 
					  publisher_id: 2
 | 
				
			||||||
  tag_name: "draft-release"
 | 
					  tag_name: "draft-release"
 | 
				
			||||||
@@ -55,3 +51,18 @@
 | 
				
			|||||||
  is_prerelease: false
 | 
					  is_prerelease: false
 | 
				
			||||||
  is_tag: false
 | 
					  is_tag: false
 | 
				
			||||||
  created_unix: 1619524806
 | 
					  created_unix: 1619524806
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- id: 5
 | 
				
			||||||
 | 
					  repo_id: 1
 | 
				
			||||||
 | 
					  publisher_id: 2
 | 
				
			||||||
 | 
					  tag_name: "v1.0"
 | 
				
			||||||
 | 
					  lower_tag_name: "v1.0"
 | 
				
			||||||
 | 
					  target: "master"
 | 
				
			||||||
 | 
					  title: "pre-release"
 | 
				
			||||||
 | 
					  note: "some text for a pre release"
 | 
				
			||||||
 | 
					  sha1: "65f1bf27bc3bf70f64657658635e66094edbcb4d"
 | 
				
			||||||
 | 
					  num_commits: 1
 | 
				
			||||||
 | 
					  is_draft: false
 | 
				
			||||||
 | 
					  is_prerelease: true
 | 
				
			||||||
 | 
					  is_tag: false
 | 
				
			||||||
 | 
					  created_unix: 946684800
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/structs"
 | 
						"code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
						"code.gitea.io/gitea/modules/timeutil"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"xorm.io/builder"
 | 
						"xorm.io/builder"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -173,6 +174,8 @@ type FindReleasesOptions struct {
 | 
				
			|||||||
	ListOptions
 | 
						ListOptions
 | 
				
			||||||
	IncludeDrafts bool
 | 
						IncludeDrafts bool
 | 
				
			||||||
	IncludeTags   bool
 | 
						IncludeTags   bool
 | 
				
			||||||
 | 
						IsPreRelease  util.OptionalBool
 | 
				
			||||||
 | 
						IsDraft       util.OptionalBool
 | 
				
			||||||
	TagNames      []string
 | 
						TagNames      []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,6 +192,12 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
 | 
				
			|||||||
	if len(opts.TagNames) > 0 {
 | 
						if len(opts.TagNames) > 0 {
 | 
				
			||||||
		cond = cond.And(builder.In("tag_name", opts.TagNames))
 | 
							cond = cond.And(builder.In("tag_name", opts.TagNames))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if !opts.IsPreRelease.IsNone() {
 | 
				
			||||||
 | 
							cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.IsTrue()})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !opts.IsDraft.IsNone() {
 | 
				
			||||||
 | 
							cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return cond
 | 
						return cond
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,6 +215,11 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er
 | 
				
			|||||||
	return rels, sess.Find(&rels)
 | 
						return rels, sess.Find(&rels)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
 | 
				
			||||||
 | 
					func CountReleasesByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) {
 | 
				
			||||||
 | 
						return x.Where(opts.toConds(repoID)).Count(new(Release))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetLatestReleaseByRepoID returns the latest release for a repository
 | 
					// GetLatestReleaseByRepoID returns the latest release for a repository
 | 
				
			||||||
func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
 | 
					func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
 | 
				
			||||||
	cond := builder.NewCond().
 | 
						cond := builder.NewCond().
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/templates"
 | 
						"code.gitea.io/gitea/modules/templates"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/translation"
 | 
						"code.gitea.io/gitea/modules/translation"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web/middleware"
 | 
						"code.gitea.io/gitea/modules/web/middleware"
 | 
				
			||||||
	"code.gitea.io/gitea/services/auth"
 | 
						"code.gitea.io/gitea/services/auth"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -319,6 +320,11 @@ func (ctx *Context) QueryBool(key string, defaults ...bool) bool {
 | 
				
			|||||||
	return (*Forms)(ctx.Req).MustBool(key, defaults...)
 | 
						return (*Forms)(ctx.Req).MustBool(key, defaults...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryOptionalBool returns request form as OptionalBool with default
 | 
				
			||||||
 | 
					func (ctx *Context) QueryOptionalBool(key string, defaults ...util.OptionalBool) util.OptionalBool {
 | 
				
			||||||
 | 
						return (*Forms)(ctx.Req).MustOptionalBool(key, defaults...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HandleText handles HTTP status code
 | 
					// HandleText handles HTTP status code
 | 
				
			||||||
func (ctx *Context) HandleText(status int, title string) {
 | 
					func (ctx *Context) HandleText(status int, title string) {
 | 
				
			||||||
	if (status/100 == 4) || (status/100 == 5) {
 | 
						if (status/100 == 4) || (status/100 == 5) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"text/template"
 | 
						"text/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Forms a new enhancement of http.Request
 | 
					// Forms a new enhancement of http.Request
 | 
				
			||||||
@@ -225,3 +226,16 @@ func (f *Forms) MustBool(key string, defaults ...bool) bool {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return v
 | 
						return v
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MustOptionalBool returns request form as OptionalBool with default
 | 
				
			||||||
 | 
					func (f *Forms) MustOptionalBool(key string, defaults ...util.OptionalBool) util.OptionalBool {
 | 
				
			||||||
 | 
						value := (*http.Request)(f).FormValue(key)
 | 
				
			||||||
 | 
						if len(value) == 0 {
 | 
				
			||||||
 | 
							return util.OptionalBoolNone
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						v, err := strconv.ParseBool((*http.Request)(f).FormValue(key))
 | 
				
			||||||
 | 
						if len(defaults) > 0 && err != nil {
 | 
				
			||||||
 | 
							return defaults[0]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return util.OptionalBoolOf(v)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
package repo
 | 
					package repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -83,6 +84,14 @@ func ListReleases(ctx *context.APIContext) {
 | 
				
			|||||||
	//   description: name of the repo
 | 
						//   description: name of the repo
 | 
				
			||||||
	//   type: string
 | 
						//   type: string
 | 
				
			||||||
	//   required: true
 | 
						//   required: true
 | 
				
			||||||
 | 
						// - name: draft
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: filter (exclude / include) drafts, if you dont have repo write access none will show
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
 | 
						// - name: pre-release
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: filter (exclude / include) pre-releases
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
	// - name: per_page
 | 
						// - name: per_page
 | 
				
			||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: page size of results, deprecated - use limit
 | 
						//   description: page size of results, deprecated - use limit
 | 
				
			||||||
@@ -100,15 +109,19 @@ func ListReleases(ctx *context.APIContext) {
 | 
				
			|||||||
	//   "200":
 | 
						//   "200":
 | 
				
			||||||
	//     "$ref": "#/responses/ReleaseList"
 | 
						//     "$ref": "#/responses/ReleaseList"
 | 
				
			||||||
	listOptions := utils.GetListOptions(ctx)
 | 
						listOptions := utils.GetListOptions(ctx)
 | 
				
			||||||
	if ctx.QueryInt("per_page") != 0 {
 | 
						if listOptions.PageSize == 0 && ctx.QueryInt("per_page") != 0 {
 | 
				
			||||||
		listOptions.PageSize = ctx.QueryInt("per_page")
 | 
							listOptions.PageSize = ctx.QueryInt("per_page")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
 | 
						opts := models.FindReleasesOptions{
 | 
				
			||||||
		ListOptions:   listOptions,
 | 
							ListOptions:   listOptions,
 | 
				
			||||||
		IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite,
 | 
							IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite,
 | 
				
			||||||
		IncludeTags:   false,
 | 
							IncludeTags:   false,
 | 
				
			||||||
	})
 | 
							IsDraft:       ctx.QueryOptionalBool("draft"),
 | 
				
			||||||
 | 
							IsPreRelease:  ctx.QueryOptionalBool("pre-release"),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
 | 
							ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -121,6 +134,16 @@ func ListReleases(ctx *context.APIContext) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		rels[i] = convert.ToRelease(release)
 | 
							rels[i] = convert.ToRelease(release)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filteredCount, err := models.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.InternalServerError(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.SetLinkHeader(int(filteredCount), listOptions.PageSize)
 | 
				
			||||||
 | 
						ctx.Header().Set("X-Total-Count", fmt.Sprint(filteredCount))
 | 
				
			||||||
 | 
						ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link")
 | 
				
			||||||
	ctx.JSON(http.StatusOK, rels)
 | 
						ctx.JSON(http.StatusOK, rels)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8076,6 +8076,18 @@
 | 
				
			|||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
            "required": true
 | 
					            "required": true
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "filter (exclude / include) drafts, if you dont have repo write access none will show",
 | 
				
			||||||
 | 
					            "name": "draft",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "filter (exclude / include) pre-releases",
 | 
				
			||||||
 | 
					            "name": "pre-release",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            "type": "integer",
 | 
					            "type": "integer",
 | 
				
			||||||
            "description": "page size of results, deprecated - use limit",
 | 
					            "description": "page size of results, deprecated - use limit",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user