diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 83ba02e316..b8427bec4e 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -522,6 +522,11 @@ func SearchRepository(ctx context.Context, opts *SearchRepoOptions) (RepositoryL return SearchRepositoryByCondition(ctx, opts, cond, true) } +// CountRepository counts repositories based on search options, +func CountRepository(ctx context.Context, opts *SearchRepoOptions) (int64, error) { + return db.GetEngine(ctx).Where(SearchRepositoryCondition(opts)).Count(new(Repository)) +} + // SearchRepositoryByCondition search repositories by condition func SearchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { sess, count, err := searchRepositoryByCondition(ctx, opts, cond) diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go index e013953c68..7097b6ea14 100644 --- a/models/repo/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -15,108 +15,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSearchRepository(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - // test search public repository on explore page - repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "repo_12", - Collaborate: util.OptionalBoolFalse, - }) - - assert.NoError(t, err) - if assert.Len(t, repos, 1) { - assert.Equal(t, "test_repo_12", repos[0].Name) - } - assert.Equal(t, int64(1), count) - - repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "test_repo", - Collaborate: util.OptionalBoolFalse, - }) - - assert.NoError(t, err) - assert.Equal(t, int64(2), count) - assert.Len(t, repos, 2) - - // test search private repository on explore page - repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "repo_13", - Private: true, - Collaborate: util.OptionalBoolFalse, - }) - - assert.NoError(t, err) - if assert.Len(t, repos, 1) { - assert.Equal(t, "test_repo_13", repos[0].Name) - } - assert.Equal(t, int64(1), count) - - repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "test_repo", - Private: true, - Collaborate: util.OptionalBoolFalse, - }) - - assert.NoError(t, err) - assert.Equal(t, int64(3), count) - assert.Len(t, repos, 3) - - // Test non existing owner - repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID}) - - assert.NoError(t, err) - assert.Empty(t, repos) - assert.Equal(t, int64(0), count) - - // Test search within description - repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "description_14", - Collaborate: util.OptionalBoolFalse, - IncludeDescription: true, - }) - - assert.NoError(t, err) - if assert.Len(t, repos, 1) { - assert.Equal(t, "test_repo_14", repos[0].Name) - } - assert.Equal(t, int64(1), count) - - // Test NOT search within description - repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ - ListOptions: db.ListOptions{ - Page: 1, - PageSize: 10, - }, - Keyword: "description_14", - Collaborate: util.OptionalBoolFalse, - IncludeDescription: false, - }) - - assert.NoError(t, err) - assert.Empty(t, repos) - assert.Equal(t, int64(0), count) - +func getTestCases() []struct { + name string + opts *repo_model.SearchRepoOptions + count int +} { testCases := []struct { name string opts *repo_model.SearchRepoOptions @@ -274,6 +177,113 @@ func TestSearchRepository(t *testing.T) { }, } + return testCases +} + +func TestSearchRepository(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // test search public repository on explore page + repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "repo_12", + Collaborate: util.OptionalBoolFalse, + }) + + assert.NoError(t, err) + if assert.Len(t, repos, 1) { + assert.Equal(t, "test_repo_12", repos[0].Name) + } + assert.Equal(t, int64(1), count) + + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "test_repo", + Collaborate: util.OptionalBoolFalse, + }) + + assert.NoError(t, err) + assert.Equal(t, int64(2), count) + assert.Len(t, repos, 2) + + // test search private repository on explore page + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "repo_13", + Private: true, + Collaborate: util.OptionalBoolFalse, + }) + + assert.NoError(t, err) + if assert.Len(t, repos, 1) { + assert.Equal(t, "test_repo_13", repos[0].Name) + } + assert.Equal(t, int64(1), count) + + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "test_repo", + Private: true, + Collaborate: util.OptionalBoolFalse, + }) + + assert.NoError(t, err) + assert.Equal(t, int64(3), count) + assert.Len(t, repos, 3) + + // Test non existing owner + repos, count, err = repo_model.SearchRepositoryByName(db.DefaultContext, &repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID}) + + assert.NoError(t, err) + assert.Empty(t, repos) + assert.Equal(t, int64(0), count) + + // Test search within description + repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "description_14", + Collaborate: util.OptionalBoolFalse, + IncludeDescription: true, + }) + + assert.NoError(t, err) + if assert.Len(t, repos, 1) { + assert.Equal(t, "test_repo_14", repos[0].Name) + } + assert.Equal(t, int64(1), count) + + // Test NOT search within description + repos, count, err = repo_model.SearchRepository(db.DefaultContext, &repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: 1, + PageSize: 10, + }, + Keyword: "description_14", + Collaborate: util.OptionalBoolFalse, + IncludeDescription: false, + }) + + assert.NoError(t, err) + assert.Empty(t, repos) + assert.Equal(t, int64(0), count) + + testCases := getTestCases() + for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { repos, count, err := repo_model.SearchRepositoryByName(db.DefaultContext, testCase.opts) @@ -349,6 +359,21 @@ func TestSearchRepository(t *testing.T) { } } +func TestCountRepository(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + testCases := getTestCases() + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + count, err := repo_model.CountRepository(db.DefaultContext, testCase.opts) + + assert.NoError(t, err) + assert.Equal(t, int64(testCase.count), count) + }) + } +} + func TestSearchRepositoryByTopicName(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 7f38ec51ba..9104c15f94 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) const ( @@ -158,6 +159,12 @@ func Home(ctx *context.Context) { ctx.Data["PageIsViewRepositories"] = true ctx.Data["IsFollowing"] = isFollowing + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + pager := context.NewPagination(int(count), setting.UI.User.RepoPagingNum, page, 5) pager.SetDefaultParams(ctx) pager.AddParam(ctx, "language", "Language") diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index ea6e7dff48..34888f1550 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -101,6 +101,12 @@ func Projects(ctx *context.Context) { project.RenderedContent = project.Description } + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + numPages := 0 if total > 0 { numPages = (int(total) - 1/setting.UI.IssuePagingNum) @@ -135,6 +141,13 @@ func RenderNewProject(ctx *context.Context) { ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink() ctx.Data["CancelLink"] = ctx.ContextUser.HomeLink() + "/-/projects" shared_user.RenderUserHeader(ctx) + + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + ctx.HTML(http.StatusOK, tplProjectsNew) } @@ -270,6 +283,12 @@ func EditProjectPost(ctx *context.Context) { shared_user.RenderUserHeader(ctx) + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + if ctx.HasError() { ctx.HTML(http.StatusOK, tplProjectsNew) return @@ -379,6 +398,12 @@ func ViewProject(ctx *context.Context) { ctx.Data["Boards"] = boards shared_user.RenderUserHeader(ctx) + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + ctx.HTML(http.StatusOK, tplProjectsView) } diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 0ef93815a3..9b1918ed16 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // prepareContextForCommonProfile store some common data into context data for user's profile related pages (including the nav menu) @@ -110,3 +111,21 @@ func RenderUserHeader(ctx *context.Context) { defer profileClose() ctx.Data["HasProfileReadme"] = profileReadmeBlob != nil } + +func LoadHeaderCount(ctx *context.Context) error { + prepareContextForCommonProfile(ctx) + + repoCount, err := repo_model.CountRepository(ctx, &repo_model.SearchRepoOptions{ + Actor: ctx.Doer, + OwnerID: ctx.ContextUser.ID, + Private: ctx.IsSigned, + Collaborate: util.OptionalBoolFalse, + IncludeDescription: setting.UI.SearchRepoDescription, + }) + if err != nil { + return err + } + ctx.Data["RepoCount"] = repoCount + + return nil +} diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 2e2c2a6e1f..d44638d48b 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -101,6 +101,12 @@ func ListPackages(ctx *context.Context) { ctx.Data["Total"] = total ctx.Data["RepositoryAccessMap"] = repositoryAccessMap + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + // TODO: context/org -> HandleOrgAssignment() can not be used if ctx.ContextUser.IsOrganization() { org := org_model.OrgFromUser(ctx.ContextUser) @@ -255,6 +261,12 @@ func ViewPackageVersion(ctx *context.Context) { } ctx.Data["HasRepositoryAccess"] = hasRepositoryAccess + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + ctx.HTML(http.StatusOK, tplPackagesView) } @@ -346,6 +358,12 @@ func ListPackageVersions(ctx *context.Context) { ctx.Data["Total"] = total + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + pager := context.NewPagination(int(total), setting.UI.PackagesPagingNum, page, 5) for k, v := range pagerParams { pager.AddParamString(k, v) diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 7f6e41d30f..87505b94b1 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -269,6 +269,12 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGi ctx.Data["Repos"] = repos ctx.Data["Total"] = total + err = shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + pager := context.NewPagination(total, pagingNum, page, 5) pager.SetDefaultParams(ctx) pager.AddParam(ctx, "tab", "TabName") diff --git a/templates/org/menu.tmpl b/templates/org/menu.tmpl index 6492e5e668..a4f602730a 100644 --- a/templates/org/menu.tmpl +++ b/templates/org/menu.tmpl @@ -2,8 +2,8 @@