From 3eb323901c6ec791294db492783e202558c2824f Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Thu, 21 May 2020 02:15:30 +0100
Subject: [PATCH] Fix repo-list private and total count bugs (#11500)

* Fix repo-list private and total count bugs

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Ensure limited and private org public repos are displayed on "private"

Signed-off-by: Andrew Thornton <art27@cantab.net>

* switch from onlyPrivate to is_private

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Generate swagger

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
---
 models/repo_list.go                    | 16 +++-----
 routers/api/v1/repo/repo.go            |  9 +++--
 templates/swagger/v1_json.tmpl         |  4 +-
 templates/user/dashboard/repolist.tmpl |  2 +-
 web_src/js/index.js                    | 54 ++++----------------------
 5 files changed, 23 insertions(+), 62 deletions(-)

diff --git a/models/repo_list.go b/models/repo_list.go
index 3e580a7229..dea88d8816 100644
--- a/models/repo_list.go
+++ b/models/repo_list.go
@@ -140,10 +140,13 @@ type SearchRepoOptions struct {
 	PriorityOwnerID int64
 	OrderBy         SearchOrderBy
 	Private         bool // Include private repositories in results
-	OnlyPrivate     bool // Include only private repositories in results
 	StarredByID     int64
 	AllPublic       bool // Include also all public repositories of users and public organisations
 	AllLimited      bool // Include also all public repositories of limited organisations
+	// None -> include public and private
+	// True -> include just private
+	// False -> incude just public
+	IsPrivate util.OptionalBool
 	// None -> include collaborative AND non-collaborative
 	// True -> include just collaborative
 	// False -> incude just non-collaborative
@@ -221,15 +224,8 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 				))))
 	}
 
-	if opts.OnlyPrivate {
-		cond = cond.And(
-			builder.Or(
-				builder.Eq{"is_private": true},
-				builder.In("owner_id", builder.Select("id").From("`user`").Where(
-					builder.And(
-						builder.Eq{"type": UserTypeOrganization},
-						builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}),
-					)))))
+	if opts.IsPrivate != util.OptionalBoolNone {
+		cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()})
 	}
 
 	if opts.Template != util.OptionalBoolNone {
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index a724ebcc37..e5055daa2b 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -78,9 +78,9 @@ func Search(ctx *context.APIContext) {
 	//   in: query
 	//   description: include private repositories this user has access to (defaults to true)
 	//   type: boolean
-	// - name: onlyPrivate
+	// - name: is_private
 	//   in: query
-	//   description: only include private repositories this user has access to (defaults to false)
+	//   description: show only pubic, private or all repositories (defaults to all)
 	//   type: boolean
 	// - name: template
 	//   in: query
@@ -133,7 +133,6 @@ func Search(ctx *context.APIContext) {
 		TopicOnly:          ctx.QueryBool("topic"),
 		Collaborate:        util.OptionalBoolNone,
 		Private:            ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
-		OnlyPrivate:        ctx.IsSigned && ctx.QueryBool("onlyPrivate"),
 		Template:           util.OptionalBoolNone,
 		StarredByID:        ctx.QueryInt64("starredBy"),
 		IncludeDescription: ctx.QueryBool("includeDesc"),
@@ -169,6 +168,10 @@ func Search(ctx *context.APIContext) {
 		opts.Archived = util.OptionalBoolOf(ctx.QueryBool("archived"))
 	}
 
+	if ctx.Query("is_private") != "" {
+		opts.IsPrivate = util.OptionalBoolOf(ctx.QueryBool("is_private"))
+	}
+
 	var sortMode = ctx.Query("sort")
 	if len(sortMode) > 0 {
 		var sortOrder = ctx.Query("order")
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index a6b24ed970..b7fa714a64 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -1771,8 +1771,8 @@
           },
           {
             "type": "boolean",
-            "description": "only include private repositories this user has access to (defaults to false)",
-            "name": "onlyPrivate",
+            "description": "show only pubic, private or all repositories (defaults to all)",
+            "name": "is_private",
             "in": "query"
           },
           {
diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl
index dc1507403c..93dda77d24 100644
--- a/templates/user/dashboard/repolist.tmpl
+++ b/templates/user/dashboard/repolist.tmpl
@@ -101,7 +101,7 @@
 			</div>
 			<div class="ui attached table segment">
 				<ul class="repo-owner-name-list">
-					<li v-for="repo in repos" :class="{'private': repo.private}" v-show="showRepo(repo)">
+					<li v-for="repo in repos" :class="{'private': repo.private}">
 						<a :href="suburl + '/' + repo.full_name">
 							<svg :class="'svg ' + repoClass(repo)" width="16" height="16" aria-hidden="true"><use :xlink:href="'#' + repoClass(repo)" /></svg>
 							<strong class="text truncate item-name">${repo.full_name}</strong>
diff --git a/web_src/js/index.js b/web_src/js/index.js
index a1b92f38a9..4042924b6f 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -2744,7 +2744,7 @@ function initVueComponents() {
         }&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode
         }${this.reposFilter !== 'all' ? '&exclusive=1' : ''
         }${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : ''
-        }${this.privateFilter === 'private' ? '&onlyPrivate=true' : ''}${this.privateFilter === 'public' ? '&private=false' : ''
+        }${this.privateFilter === 'private' ? '&is_private=true' : ''}${this.privateFilter === 'public' ? '&is_private=false' : ''
         }`;
       },
       repoTypeCount() {
@@ -2910,56 +2910,18 @@ function initVueComponents() {
         this.searchRepos();
       },
 
-      showArchivedRepo(repo) {
-        switch (this.archivedFilter) {
-          case 'both':
-            return true;
-          case 'unarchived':
-            return !repo.archived;
-          case 'archived':
-            return repo.archived;
-          default:
-            return !repo.archived;
-        }
-      },
-
-      showPrivateRepo(repo) {
-        switch (this.privateFilter) {
-          case 'both':
-            return true;
-          case 'public':
-            return !repo.private;
-          case 'private':
-            return repo.private;
-          default:
-            return true;
-        }
-      },
-
-      showFilteredRepo(repo) {
-        switch (this.reposFilter) {
-          case 'sources':
-            return repo.owner.id === this.uid && !repo.mirror && !repo.fork;
-          case 'forks':
-            return repo.owner.id === this.uid && !repo.mirror && repo.fork;
-          case 'mirrors':
-            return repo.mirror;
-          case 'collaborative':
-            return repo.owner.id !== this.uid && !repo.mirror;
-          default:
-            return true;
-        }
-      },
-
-      showRepo(repo) {
-        return this.showArchivedRepo(repo) && this.showPrivateRepo(repo) && this.showFilteredRepo(repo);
-      },
-
       searchRepos() {
         const self = this;
 
         this.isLoading = true;
 
+        if (!this.reposTotalCount) {
+          const totalCountSearchURL = `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&q=&page=1&mode=`;
+          $.getJSON(totalCountSearchURL, (_result, _textStatus, request) => {
+            self.reposTotalCount = request.getResponseHeader('X-Total-Count');
+          });
+        }
+
         const searchedMode = this.repoTypes[this.reposFilter].searchMode;
         const searchedURL = this.searchURL;
         const searchedQuery = this.searchQuery;