mirror of https://github.com/go-gitea/gitea.git
feat: support search bar on star tab of user profile. (#917)
* feat: support search bar on star tab of user profile. * fix: update testing. * fix: Using loadAttributes * fix: remove empty line. * remove LOWER Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>pull/927/head
parent
7eb8daffa3
commit
23aba523b5
|
@ -1778,13 +1778,15 @@ type SearchRepoOptions struct {
|
||||||
Searcher *User //ID of the person who's seeking
|
Searcher *User //ID of the person who's seeking
|
||||||
OrderBy string
|
OrderBy string
|
||||||
Private bool // Include private repositories in results
|
Private bool // Include private repositories in results
|
||||||
|
Starred bool
|
||||||
Page int
|
Page int
|
||||||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchRepositoryByName takes keyword and part of repository name to search,
|
// SearchRepositoryByName takes keyword and part of repository name to search,
|
||||||
// it returns results in given range and number of total results.
|
// it returns results in given range and number of total results.
|
||||||
func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int64, _ error) {
|
func SearchRepositoryByName(opts *SearchRepoOptions) (repos RepositoryList, _ int64, _ error) {
|
||||||
|
var sess *xorm.Session
|
||||||
if len(opts.Keyword) == 0 {
|
if len(opts.Keyword) == 0 {
|
||||||
return repos, 0, nil
|
return repos, 0, nil
|
||||||
}
|
}
|
||||||
|
@ -1796,9 +1798,17 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int
|
||||||
|
|
||||||
repos = make([]*Repository, 0, opts.PageSize)
|
repos = make([]*Repository, 0, opts.PageSize)
|
||||||
|
|
||||||
|
if opts.Starred && opts.OwnerID > 0 {
|
||||||
|
sess = x.
|
||||||
|
Join("INNER", "star", "star.repo_id = repository.id").
|
||||||
|
Where("star.uid = ?", opts.OwnerID).
|
||||||
|
And("lower_name LIKE ?", "%"+opts.Keyword+"%")
|
||||||
|
} else {
|
||||||
|
sess = x.Where("lower_name LIKE ?", "%"+opts.Keyword+"%")
|
||||||
|
}
|
||||||
|
|
||||||
// Append conditions
|
// Append conditions
|
||||||
sess := x.Where("LOWER(lower_name) LIKE ?", "%"+opts.Keyword+"%")
|
if !opts.Starred && opts.OwnerID > 0 {
|
||||||
if opts.OwnerID > 0 {
|
|
||||||
sess.And("owner_id = ?", opts.OwnerID)
|
sess.And("owner_id = ?", opts.OwnerID)
|
||||||
}
|
}
|
||||||
if !opts.Private {
|
if !opts.Private {
|
||||||
|
@ -1831,10 +1841,20 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int
|
||||||
return nil, 0, fmt.Errorf("Count: %v", err)
|
return nil, 0, fmt.Errorf("Count: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, count, sess.
|
if err = sess.
|
||||||
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
||||||
OrderBy(opts.OrderBy).
|
OrderBy(opts.OrderBy).
|
||||||
Find(&repos)
|
Find(&repos); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("Repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Starred {
|
||||||
|
if err = repos.loadAttributes(x); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repos, count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRepositoryArchives deletes all repositories' archives.
|
// DeleteRepositoryArchives deletes all repositories' archives.
|
||||||
|
|
|
@ -73,12 +73,12 @@ func (repo *Repository) GetStargazers(page int) ([]*User, error) {
|
||||||
// GetStarredRepos returns the repos the user starred.
|
// GetStarredRepos returns the repos the user starred.
|
||||||
func (u *User) GetStarredRepos(private bool, page, pageSize int, orderBy string) (repos []*Repository, err error) {
|
func (u *User) GetStarredRepos(private bool, page, pageSize int, orderBy string) (repos []*Repository, err error) {
|
||||||
if len(orderBy) == 0 {
|
if len(orderBy) == 0 {
|
||||||
orderBy = "star.id"
|
orderBy = "updated_unix DESC"
|
||||||
}
|
}
|
||||||
sess := x.
|
sess := x.
|
||||||
Join("INNER", "star", "star.repo_id = repository.id").
|
Join("INNER", "star", "star.repo_id = repository.id").
|
||||||
Where("star.uid = ?", u.ID).
|
Where("star.uid = ?", u.ID).
|
||||||
Desc(orderBy)
|
OrderBy(orderBy)
|
||||||
|
|
||||||
if !private {
|
if !private {
|
||||||
sess = sess.And("is_private = ?", false)
|
sess = sess.And("is_private = ?", false)
|
||||||
|
|
|
@ -61,8 +61,8 @@ func TestUser_GetStarredRepos(t *testing.T) {
|
||||||
starred, err = user.GetStarredRepos(true, 1, 10, "")
|
starred, err = user.GetStarredRepos(true, 1, 10, "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, starred, 2)
|
assert.Len(t, starred, 2)
|
||||||
assert.Equal(t, int64(4), starred[0].ID)
|
assert.Equal(t, int64(2), starred[0].ID)
|
||||||
assert.Equal(t, int64(2), starred[1].ID)
|
assert.Equal(t, int64(4), starred[1].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUser_GetStarredRepos2(t *testing.T) {
|
func TestUser_GetStarredRepos2(t *testing.T) {
|
||||||
|
|
|
@ -90,6 +90,44 @@ func Profile(ctx *context.Context) {
|
||||||
|
|
||||||
tab := ctx.Query("tab")
|
tab := ctx.Query("tab")
|
||||||
ctx.Data["TabName"] = tab
|
ctx.Data["TabName"] = tab
|
||||||
|
|
||||||
|
page := ctx.QueryInt("page")
|
||||||
|
if page <= 0 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
repos []*models.Repository
|
||||||
|
count int64
|
||||||
|
orderBy string
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx.Data["SortType"] = ctx.Query("sort")
|
||||||
|
switch ctx.Query("sort") {
|
||||||
|
case "newest":
|
||||||
|
orderBy = "created_unix DESC"
|
||||||
|
case "oldest":
|
||||||
|
orderBy = "created_unix ASC"
|
||||||
|
case "recentupdate":
|
||||||
|
orderBy = "updated_unix DESC"
|
||||||
|
case "leastupdate":
|
||||||
|
orderBy = "updated_unix ASC"
|
||||||
|
case "reversealphabetically":
|
||||||
|
orderBy = "name DESC"
|
||||||
|
case "alphabetically":
|
||||||
|
orderBy = "name ASC"
|
||||||
|
default:
|
||||||
|
ctx.Data["SortType"] = "recentupdate"
|
||||||
|
orderBy = "updated_unix DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default sort value if sort is empty.
|
||||||
|
if ctx.Query("sort") == "" {
|
||||||
|
ctx.Data["SortType"] = "recentupdate"
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword := strings.Trim(ctx.Query("q"), " ")
|
||||||
|
ctx.Data["Keyword"] = keyword
|
||||||
switch tab {
|
switch tab {
|
||||||
case "activity":
|
case "activity":
|
||||||
retrieveFeeds(ctx, ctxUser, -1, 0, !showPrivate)
|
retrieveFeeds(ctx, ctxUser, -1, 0, !showPrivate)
|
||||||
|
@ -97,66 +135,39 @@ func Profile(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "stars":
|
case "stars":
|
||||||
page := ctx.QueryInt("page")
|
ctx.Data["PageIsProfileStarList"] = true
|
||||||
if page <= 0 {
|
if len(keyword) == 0 {
|
||||||
page = 1
|
repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy)
|
||||||
}
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetStarredRepos", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
repos, err := ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, "")
|
count, err = ctxUser.GetStarredRepoCount(showPrivate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(500, "GetStarredRepos", err)
|
ctx.Handle(500, "GetStarredRepoCount", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
counts, err := ctxUser.GetStarredRepoCount(showPrivate)
|
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||||
if err != nil {
|
Keyword: keyword,
|
||||||
ctx.Handle(500, "GetStarredRepoCount", err)
|
OwnerID: ctxUser.ID,
|
||||||
return
|
OrderBy: orderBy,
|
||||||
|
Private: showPrivate,
|
||||||
|
Page: page,
|
||||||
|
PageSize: setting.UI.User.RepoPagingNum,
|
||||||
|
Starred: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "SearchRepositoryByName", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Repos"] = repos
|
ctx.Data["Repos"] = repos
|
||||||
ctx.Data["Page"] = paginater.New(int(counts), setting.UI.User.RepoPagingNum, page, 5)
|
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
|
||||||
ctx.Data["Total"] = int(counts)
|
ctx.Data["Total"] = count
|
||||||
ctx.Data["Tabs"] = "stars"
|
|
||||||
default:
|
default:
|
||||||
page := ctx.QueryInt("page")
|
|
||||||
if page <= 0 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
repos []*models.Repository
|
|
||||||
count int64
|
|
||||||
err error
|
|
||||||
orderBy string
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.Data["SortType"] = ctx.Query("sort")
|
|
||||||
switch ctx.Query("sort") {
|
|
||||||
case "newest":
|
|
||||||
orderBy = "created_unix DESC"
|
|
||||||
case "oldest":
|
|
||||||
orderBy = "created_unix ASC"
|
|
||||||
case "recentupdate":
|
|
||||||
orderBy = "updated_unix DESC"
|
|
||||||
case "leastupdate":
|
|
||||||
orderBy = "updated_unix ASC"
|
|
||||||
case "reversealphabetically":
|
|
||||||
orderBy = "name DESC"
|
|
||||||
case "alphabetically":
|
|
||||||
orderBy = "name ASC"
|
|
||||||
default:
|
|
||||||
ctx.Data["SortType"] = "recentupdate"
|
|
||||||
orderBy = "updated_unix DESC"
|
|
||||||
}
|
|
||||||
|
|
||||||
// set default sort value if sort is empty.
|
|
||||||
if ctx.Query("sort") == "" {
|
|
||||||
ctx.Data["SortType"] = "recentupdate"
|
|
||||||
}
|
|
||||||
|
|
||||||
keyword := strings.Trim(ctx.Query("q"), " ")
|
|
||||||
ctx.Data["Keyword"] = keyword
|
|
||||||
if len(keyword) == 0 {
|
if len(keyword) == 0 {
|
||||||
var total int
|
var total int
|
||||||
repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy)
|
repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy)
|
||||||
|
|
|
@ -2,21 +2,21 @@
|
||||||
{{if gt .TotalPages 1}}
|
{{if gt .TotalPages 1}}
|
||||||
<div class="center page buttons">
|
<div class="center page buttons">
|
||||||
<div class="ui borderless pagination menu">
|
<div class="ui borderless pagination menu">
|
||||||
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}?q={{$.Keyword}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a>
|
<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&tab={{$.TabName}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a>
|
||||||
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>
|
<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>
|
||||||
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
|
<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
|
||||||
</a>
|
</a>
|
||||||
{{range .Pages}}
|
{{range .Pages}}
|
||||||
{{if eq .Num -1}}
|
{{if eq .Num -1}}
|
||||||
<a class="disabled item">...</a>
|
<a class="disabled item">...</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>{{.Num}}</a>
|
<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>{{.Num}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>
|
<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>
|
||||||
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
|
{{$.i18n.Tr "repo.issues.next"}} <i class="icon right arrow"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}&q={{$.Keyword}}&tab={{$.Tabs}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a>
|
<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}&q={{$.Keyword}}&tab={{$.TabName}}">{{$.i18n.Tr "admin.last_page"}} <i class="angle double right icon"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{{range .Repos}}
|
{{range .Repos}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="ui header">
|
<div class="ui header">
|
||||||
<a class="name" href="{{AppSubUrl}}/{{if .Owner}}{{.Owner.Name}}{{else if $.Org}}{{$.Org.Name}}{{else}}{{$.Owner.Name}}{{end}}/{{.Name}}">{{if $.PageIsExplore}}{{.Owner.Name}} / {{end}}{{.Name}}</a>
|
<a class="name" href="{{AppSubUrl}}/{{if .Owner}}{{.Owner.Name}}{{else if $.Org}}{{$.Org.Name}}{{else}}{{$.Owner.Name}}{{end}}/{{.Name}}">{{if or $.PageIsExplore $.PageIsProfileStarList }}{{.Owner.Name}} / {{end}}{{.Name}}</a>
|
||||||
{{if .IsPrivate}}
|
{{if .IsPrivate}}
|
||||||
<span class="text gold"><i class="octicon octicon-lock"></i></span>
|
<span class="text gold"><i class="octicon octicon-lock"></i></span>
|
||||||
{{else if .IsFork}}
|
{{else if .IsFork}}
|
||||||
|
|
|
@ -6,18 +6,19 @@
|
||||||
<i class="dropdown icon"></i>
|
<i class="dropdown icon"></i>
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "newest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if or (eq .SortType "newest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="ui form" style="max-width: 90%">
|
<form class="ui form" style="max-width: 90%">
|
||||||
<div class="ui fluid action input">
|
<div class="ui fluid action input">
|
||||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
||||||
|
<input type="hidden" name="tab" value="{{$.TabName}}">
|
||||||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .TabName "stars"}}
|
{{else if eq .TabName "stars"}}
|
||||||
<div class="stars">
|
<div class="stars">
|
||||||
|
{{template "explore/search" .}}
|
||||||
{{template "explore/repo_list" .}}
|
{{template "explore/repo_list" .}}
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue