Browse Source

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>
Bo-Yi Wu 3 years ago
parent
commit
23aba523b5

+ 25 - 5
models/repo.go

@@ -1778,13 +1778,15 @@ type SearchRepoOptions struct {
1778 1778
 	Searcher *User //ID of the person who's seeking
1779 1779
 	OrderBy  string
1780 1780
 	Private  bool // Include private repositories in results
1781
+	Starred  bool
1781 1782
 	Page     int
1782 1783
 	PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
1783 1784
 }
1784 1785
 
1785 1786
 // SearchRepositoryByName takes keyword and part of repository name to search,
1786 1787
 // it returns results in given range and number of total results.
1787
-func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int64, _ error) {
1788
+func SearchRepositoryByName(opts *SearchRepoOptions) (repos RepositoryList, _ int64, _ error) {
1789
+	var sess *xorm.Session
1788 1790
 	if len(opts.Keyword) == 0 {
1789 1791
 		return repos, 0, nil
1790 1792
 	}
@@ -1796,9 +1798,17 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int
1796 1798
 
1797 1799
 	repos = make([]*Repository, 0, opts.PageSize)
1798 1800
 
1801
+	if opts.Starred && opts.OwnerID > 0 {
1802
+		sess = x.
1803
+			Join("INNER", "star", "star.repo_id = repository.id").
1804
+			Where("star.uid = ?", opts.OwnerID).
1805
+			And("lower_name LIKE ?", "%"+opts.Keyword+"%")
1806
+	} else {
1807
+		sess = x.Where("lower_name LIKE ?", "%"+opts.Keyword+"%")
1808
+	}
1809
+
1799 1810
 	// Append conditions
1800
-	sess := x.Where("LOWER(lower_name) LIKE ?", "%"+opts.Keyword+"%")
1801
-	if opts.OwnerID > 0 {
1811
+	if !opts.Starred && opts.OwnerID > 0 {
1802 1812
 		sess.And("owner_id = ?", opts.OwnerID)
1803 1813
 	}
1804 1814
 	if !opts.Private {
@@ -1831,10 +1841,20 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos []*Repository, _ int
1831 1841
 		return nil, 0, fmt.Errorf("Count: %v", err)
1832 1842
 	}
1833 1843
 
1834
-	return repos, count, sess.
1844
+	if err = sess.
1835 1845
 		Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
1836 1846
 		OrderBy(opts.OrderBy).
1837
-		Find(&repos)
1847
+		Find(&repos); err != nil {
1848
+		return nil, 0, fmt.Errorf("Repo: %v", err)
1849
+	}
1850
+
1851
+	if opts.Starred {
1852
+		if err = repos.loadAttributes(x); err != nil {
1853
+			return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
1854
+		}
1855
+	}
1856
+
1857
+	return repos, count, nil
1838 1858
 }
1839 1859
 
1840 1860
 // DeleteRepositoryArchives deletes all repositories' archives.

+ 2 - 2
models/star.go

@@ -73,12 +73,12 @@ func (repo *Repository) GetStargazers(page int) ([]*User, error) {
73 73
 // GetStarredRepos returns the repos the user starred.
74 74
 func (u *User) GetStarredRepos(private bool, page, pageSize int, orderBy string) (repos []*Repository, err error) {
75 75
 	if len(orderBy) == 0 {
76
-		orderBy = "star.id"
76
+		orderBy = "updated_unix DESC"
77 77
 	}
78 78
 	sess := x.
79 79
 		Join("INNER", "star", "star.repo_id = repository.id").
80 80
 		Where("star.uid = ?", u.ID).
81
-		Desc(orderBy)
81
+		OrderBy(orderBy)
82 82
 
83 83
 	if !private {
84 84
 		sess = sess.And("is_private = ?", false)

+ 2 - 2
models/star_test.go

@@ -61,8 +61,8 @@ func TestUser_GetStarredRepos(t *testing.T) {
61 61
 	starred, err = user.GetStarredRepos(true, 1, 10, "")
62 62
 	assert.NoError(t, err)
63 63
 	assert.Len(t, starred, 2)
64
-	assert.Equal(t, int64(4), starred[0].ID)
65
-	assert.Equal(t, int64(2), starred[1].ID)
64
+	assert.Equal(t, int64(2), starred[0].ID)
65
+	assert.Equal(t, int64(4), starred[1].ID)
66 66
 }
67 67
 
68 68
 func TestUser_GetStarredRepos2(t *testing.T) {

+ 66 - 55
routers/user/profile.go

@@ -90,6 +90,44 @@ func Profile(ctx *context.Context) {
90 90
 
91 91
 	tab := ctx.Query("tab")
92 92
 	ctx.Data["TabName"] = tab
93
+
94
+	page := ctx.QueryInt("page")
95
+	if page <= 0 {
96
+		page = 1
97
+	}
98
+
99
+	var (
100
+		repos   []*models.Repository
101
+		count   int64
102
+		orderBy string
103
+	)
104
+
105
+	ctx.Data["SortType"] = ctx.Query("sort")
106
+	switch ctx.Query("sort") {
107
+	case "newest":
108
+		orderBy = "created_unix DESC"
109
+	case "oldest":
110
+		orderBy = "created_unix ASC"
111
+	case "recentupdate":
112
+		orderBy = "updated_unix DESC"
113
+	case "leastupdate":
114
+		orderBy = "updated_unix ASC"
115
+	case "reversealphabetically":
116
+		orderBy = "name DESC"
117
+	case "alphabetically":
118
+		orderBy = "name ASC"
119
+	default:
120
+		ctx.Data["SortType"] = "recentupdate"
121
+		orderBy = "updated_unix DESC"
122
+	}
123
+
124
+	// set default sort value if sort is empty.
125
+	if ctx.Query("sort") == "" {
126
+		ctx.Data["SortType"] = "recentupdate"
127
+	}
128
+
129
+	keyword := strings.Trim(ctx.Query("q"), " ")
130
+	ctx.Data["Keyword"] = keyword
93 131
 	switch tab {
94 132
 	case "activity":
95 133
 		retrieveFeeds(ctx, ctxUser, -1, 0, !showPrivate)
@@ -97,66 +135,39 @@ func Profile(ctx *context.Context) {
97 135
 			return
98 136
 		}
99 137
 	case "stars":
100
-		page := ctx.QueryInt("page")
101
-		if page <= 0 {
102
-			page = 1
103
-		}
104
-
105
-		repos, err := ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, "")
106
-		if err != nil {
107
-			ctx.Handle(500, "GetStarredRepos", err)
108
-			return
109
-		}
138
+		ctx.Data["PageIsProfileStarList"] = true
139
+		if len(keyword) == 0 {
140
+			repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy)
141
+			if err != nil {
142
+				ctx.Handle(500, "GetStarredRepos", err)
143
+				return
144
+			}
110 145
 
111
-		counts, err := ctxUser.GetStarredRepoCount(showPrivate)
112
-		if err != nil {
113
-			ctx.Handle(500, "GetStarredRepoCount", err)
114
-			return
146
+			count, err = ctxUser.GetStarredRepoCount(showPrivate)
147
+			if err != nil {
148
+				ctx.Handle(500, "GetStarredRepoCount", err)
149
+				return
150
+			}
151
+		} else {
152
+			repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
153
+				Keyword:  keyword,
154
+				OwnerID:  ctxUser.ID,
155
+				OrderBy:  orderBy,
156
+				Private:  showPrivate,
157
+				Page:     page,
158
+				PageSize: setting.UI.User.RepoPagingNum,
159
+				Starred:  true,
160
+			})
161
+			if err != nil {
162
+				ctx.Handle(500, "SearchRepositoryByName", err)
163
+				return
164
+			}
115 165
 		}
116 166
 
117 167
 		ctx.Data["Repos"] = repos
118
-		ctx.Data["Page"] = paginater.New(int(counts), setting.UI.User.RepoPagingNum, page, 5)
119
-		ctx.Data["Total"] = int(counts)
120
-		ctx.Data["Tabs"] = "stars"
168
+		ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
169
+		ctx.Data["Total"] = count
121 170
 	default:
122
-		page := ctx.QueryInt("page")
123
-		if page <= 0 {
124
-			page = 1
125
-		}
126
-
127
-		var (
128
-			repos   []*models.Repository
129
-			count   int64
130
-			err     error
131
-			orderBy string
132
-		)
133
-
134
-		ctx.Data["SortType"] = ctx.Query("sort")
135
-		switch ctx.Query("sort") {
136
-		case "newest":
137
-			orderBy = "created_unix DESC"
138
-		case "oldest":
139
-			orderBy = "created_unix ASC"
140
-		case "recentupdate":
141
-			orderBy = "updated_unix DESC"
142
-		case "leastupdate":
143
-			orderBy = "updated_unix ASC"
144
-		case "reversealphabetically":
145
-			orderBy = "name DESC"
146
-		case "alphabetically":
147
-			orderBy = "name ASC"
148
-		default:
149
-			ctx.Data["SortType"] = "recentupdate"
150
-			orderBy = "updated_unix DESC"
151
-		}
152
-
153
-		// set default sort value if sort is empty.
154
-		if ctx.Query("sort") == "" {
155
-			ctx.Data["SortType"] = "recentupdate"
156
-		}
157
-
158
-		keyword := strings.Trim(ctx.Query("q"), " ")
159
-		ctx.Data["Keyword"] = keyword
160 171
 		if len(keyword) == 0 {
161 172
 			var total int
162 173
 			repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy)

+ 5 - 5
templates/base/paginate.tmpl

@@ -2,21 +2,21 @@
2 2
 	{{if gt .TotalPages 1}}
3 3
 		<div class="center page buttons">
4 4
 			<div class="ui borderless pagination menu">
5
-				<a class="{{if .IsFirst}}disabled{{end}} item" href="{{$.Link}}?q={{$.Keyword}}"><i class="angle double left icon"></i> {{$.i18n.Tr "admin.first_page"}}</a>
6
-				<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>
5
+				<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>
6
+				<a class="{{if not .HasPrevious}}disabled{{end}} item" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>
7 7
 					<i class="left arrow icon"></i> {{$.i18n.Tr "repo.issues.previous"}}
8 8
 				</a>
9 9
 				{{range .Pages}}
10 10
 					{{if eq .Num -1}}
11 11
 						<a class="disabled item">...</a>
12 12
 					{{else}}
13
-						<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>{{.Num}}</a>
13
+						<a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.Link}}?page={{.Num}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>{{.Num}}</a>
14 14
 					{{end}}
15 15
 				{{end}}
16
-				<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}&tab={{$.Tabs}}"{{end}}>
16
+				<a class="{{if not .HasNext}}disabled{{end}} item" {{if .HasNext}}href="{{$.Link}}?page={{.Next}}&q={{$.Keyword}}&tab={{$.TabName}}"{{end}}>
17 17
 					{{$.i18n.Tr "repo.issues.next"}}&nbsp;<i class="icon right arrow"></i>
18 18
 				</a>
19
-				<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}&q={{$.Keyword}}&tab={{$.Tabs}}">{{$.i18n.Tr "admin.last_page"}}&nbsp;<i class="angle double right icon"></i></a>
19
+				<a class="{{if .IsLast}}disabled{{end}} item" href="{{$.Link}}?page={{.TotalPages}}&q={{$.Keyword}}&tab={{$.TabName}}">{{$.i18n.Tr "admin.last_page"}}&nbsp;<i class="angle double right icon"></i></a>
20 20
 			</div>
21 21
 		</div>
22 22
 	{{end}}

+ 1 - 1
templates/explore/repo_list.tmpl

@@ -2,7 +2,7 @@
2 2
 	{{range .Repos}}
3 3
 		<div class="item">
4 4
 			<div class="ui header">
5
-				<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>
5
+				<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>
6 6
 				{{if .IsPrivate}}
7 7
 					<span class="text gold"><i class="octicon octicon-lock"></i></span>
8 8
 				{{else if .IsFork}}

+ 7 - 6
templates/explore/search.tmpl

@@ -6,18 +6,19 @@
6 6
 			<i class="dropdown icon"></i>
7 7
 		</span>
8 8
 		<div class="menu">
9
-			<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>
10
-			<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
11
-			<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
12
-			<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>
13
-			<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
14
-			<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
9
+			<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>
10
+			<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>
11
+			<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>
12
+			<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>
13
+			<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>
14
+			<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>
15 15
 		</div>
16 16
 	</div>
17 17
 </div>
18 18
 <form class="ui form" style="max-width: 90%">
19 19
 	<div class="ui fluid action input">
20 20
 	  <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
21
+	  <input type="hidden" name="tab" value="{{$.TabName}}">
21 22
 	  <button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
22 23
 	</div>
23 24
 </form>

+ 1 - 0
templates/user/profile.tmpl

@@ -92,6 +92,7 @@
92 92
 					</div>
93 93
 				{{else if eq .TabName "stars"}}
94 94
 					<div class="stars">
95
+						{{template "explore/search" .}}
95 96
 						{{template "explore/repo_list" .}}
96 97
 						{{template "base/paginate" .}}
97 98
 					</div>