mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-04 05:18:25 +00:00 
			
		
		
		
	Global code search support (#3664)
* add global code search on explore * fix bug when no anyone public repos * change the icon * fix typo and add UnitTypeCode check for login non-admin user * fix ui description when no match
This commit is contained in:
		@@ -1945,6 +1945,12 @@ func GetRepositoryByID(id int64) (*Repository, error) {
 | 
				
			|||||||
	return getRepositoryByID(x, id)
 | 
						return getRepositoryByID(x, id)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetRepositoriesMapByIDs returns the repositories by given id slice.
 | 
				
			||||||
 | 
					func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) {
 | 
				
			||||||
 | 
						var repos = make(map[int64]*Repository, len(ids))
 | 
				
			||||||
 | 
						return repos, x.In("id", ids).Find(&repos)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserRepositories returns a list of repositories of given user.
 | 
					// GetUserRepositories returns a list of repositories of given user.
 | 
				
			||||||
func GetUserRepositories(userID int64, private bool, page, pageSize int, orderBy string) ([]*Repository, error) {
 | 
					func GetUserRepositories(userID int64, private bool, page, pageSize int, orderBy string) ([]*Repository, error) {
 | 
				
			||||||
	if len(orderBy) == 0 {
 | 
						if len(orderBy) == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -249,3 +249,28 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return repos, count, nil
 | 
						return repos, count, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
 | 
				
			||||||
 | 
					func FindUserAccessibleRepoIDs(userID int64) ([]int64, error) {
 | 
				
			||||||
 | 
						var accessCond builder.Cond = builder.Eq{"is_private": false}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if userID > 0 {
 | 
				
			||||||
 | 
							accessCond = accessCond.Or(
 | 
				
			||||||
 | 
								builder.Eq{"owner_id": userID},
 | 
				
			||||||
 | 
								builder.And(
 | 
				
			||||||
 | 
									builder.Expr("id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", userID),
 | 
				
			||||||
 | 
									builder.Neq{"owner_id": userID},
 | 
				
			||||||
 | 
								),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repoIDs := make([]int64, 0, 10)
 | 
				
			||||||
 | 
						if err := x.
 | 
				
			||||||
 | 
							Table("repository").
 | 
				
			||||||
 | 
							Cols("id").
 | 
				
			||||||
 | 
							Where(accessCond).
 | 
				
			||||||
 | 
							Find(&repoIDs); err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return repoIDs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ import (
 | 
				
			|||||||
	"github.com/blevesearch/bleve/analysis/token/lowercase"
 | 
						"github.com/blevesearch/bleve/analysis/token/lowercase"
 | 
				
			||||||
	"github.com/blevesearch/bleve/analysis/token/unique"
 | 
						"github.com/blevesearch/bleve/analysis/token/unique"
 | 
				
			||||||
	"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
 | 
						"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
 | 
				
			||||||
 | 
						"github.com/blevesearch/bleve/search/query"
 | 
				
			||||||
	"github.com/ethantkoenig/rupture"
 | 
						"github.com/ethantkoenig/rupture"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,6 +159,7 @@ func DeleteRepoFromIndexer(repoID int64) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// RepoSearchResult result of performing a search in a repo
 | 
					// RepoSearchResult result of performing a search in a repo
 | 
				
			||||||
type RepoSearchResult struct {
 | 
					type RepoSearchResult struct {
 | 
				
			||||||
 | 
						RepoID     int64
 | 
				
			||||||
	StartIndex int
 | 
						StartIndex int
 | 
				
			||||||
	EndIndex   int
 | 
						EndIndex   int
 | 
				
			||||||
	Filename   string
 | 
						Filename   string
 | 
				
			||||||
@@ -166,17 +168,29 @@ type RepoSearchResult struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SearchRepoByKeyword searches for files in the specified repo.
 | 
					// SearchRepoByKeyword searches for files in the specified repo.
 | 
				
			||||||
// Returns the matching file-paths
 | 
					// Returns the matching file-paths
 | 
				
			||||||
func SearchRepoByKeyword(repoID int64, keyword string, page, pageSize int) (int64, []*RepoSearchResult, error) {
 | 
					func SearchRepoByKeyword(repoIDs []int64, keyword string, page, pageSize int) (int64, []*RepoSearchResult, error) {
 | 
				
			||||||
	phraseQuery := bleve.NewMatchPhraseQuery(keyword)
 | 
						phraseQuery := bleve.NewMatchPhraseQuery(keyword)
 | 
				
			||||||
	phraseQuery.FieldVal = "Content"
 | 
						phraseQuery.FieldVal = "Content"
 | 
				
			||||||
	phraseQuery.Analyzer = repoIndexerAnalyzer
 | 
						phraseQuery.Analyzer = repoIndexerAnalyzer
 | 
				
			||||||
	indexerQuery := bleve.NewConjunctionQuery(
 | 
					
 | 
				
			||||||
		numericEqualityQuery(repoID, "RepoID"),
 | 
						var indexerQuery query.Query
 | 
				
			||||||
 | 
						if len(repoIDs) > 0 {
 | 
				
			||||||
 | 
							var repoQueries = make([]query.Query, 0, len(repoIDs))
 | 
				
			||||||
 | 
							for _, repoID := range repoIDs {
 | 
				
			||||||
 | 
								repoQueries = append(repoQueries, numericEqualityQuery(repoID, "RepoID"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							indexerQuery = bleve.NewConjunctionQuery(
 | 
				
			||||||
 | 
								bleve.NewDisjunctionQuery(repoQueries...),
 | 
				
			||||||
			phraseQuery,
 | 
								phraseQuery,
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							indexerQuery = phraseQuery
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	from := (page - 1) * pageSize
 | 
						from := (page - 1) * pageSize
 | 
				
			||||||
	searchRequest := bleve.NewSearchRequestOptions(indexerQuery, pageSize, from, false)
 | 
						searchRequest := bleve.NewSearchRequestOptions(indexerQuery, pageSize, from, false)
 | 
				
			||||||
	searchRequest.Fields = []string{"Content"}
 | 
						searchRequest.Fields = []string{"Content", "RepoID"}
 | 
				
			||||||
	searchRequest.IncludeLocations = true
 | 
						searchRequest.IncludeLocations = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result, err := repoIndexer.Search(searchRequest)
 | 
						result, err := repoIndexer.Search(searchRequest)
 | 
				
			||||||
@@ -199,6 +213,7 @@ func SearchRepoByKeyword(repoID int64, keyword string, page, pageSize int) (int6
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		searchResults[i] = &RepoSearchResult{
 | 
							searchResults[i] = &RepoSearchResult{
 | 
				
			||||||
 | 
								RepoID:     int64(hit.Fields["RepoID"].(float64)),
 | 
				
			||||||
			StartIndex: startIndex,
 | 
								StartIndex: startIndex,
 | 
				
			||||||
			EndIndex:   endIndex,
 | 
								EndIndex:   endIndex,
 | 
				
			||||||
			Filename:   filenameOfIndexerID(hit.ID),
 | 
								Filename:   filenameOfIndexerID(hit.ID),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Result a search result to display
 | 
					// Result a search result to display
 | 
				
			||||||
type Result struct {
 | 
					type Result struct {
 | 
				
			||||||
 | 
						RepoID         int64
 | 
				
			||||||
	Filename       string
 | 
						Filename       string
 | 
				
			||||||
	HighlightClass string
 | 
						HighlightClass string
 | 
				
			||||||
	LineNumbers    []int
 | 
						LineNumbers    []int
 | 
				
			||||||
@@ -98,6 +99,7 @@ func searchResult(result *indexer.RepoSearchResult, startIndex, endIndex int) (*
 | 
				
			|||||||
		index += len(line)
 | 
							index += len(line)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &Result{
 | 
						return &Result{
 | 
				
			||||||
 | 
							RepoID:         result.RepoID,
 | 
				
			||||||
		Filename:       result.Filename,
 | 
							Filename:       result.Filename,
 | 
				
			||||||
		HighlightClass: highlight.FileNameToHighlightClass(result.Filename),
 | 
							HighlightClass: highlight.FileNameToHighlightClass(result.Filename),
 | 
				
			||||||
		LineNumbers:    lineNumbers,
 | 
							LineNumbers:    lineNumbers,
 | 
				
			||||||
@@ -106,12 +108,12 @@ func searchResult(result *indexer.RepoSearchResult, startIndex, endIndex int) (*
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PerformSearch perform a search on a repository
 | 
					// PerformSearch perform a search on a repository
 | 
				
			||||||
func PerformSearch(repoID int64, keyword string, page, pageSize int) (int, []*Result, error) {
 | 
					func PerformSearch(repoIDs []int64, keyword string, page, pageSize int) (int, []*Result, error) {
 | 
				
			||||||
	if len(keyword) == 0 {
 | 
						if len(keyword) == 0 {
 | 
				
			||||||
		return 0, nil, nil
 | 
							return 0, nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	total, results, err := indexer.SearchRepoByKeyword(repoID, keyword, page, pageSize)
 | 
						total, results, err := indexer.SearchRepoByKeyword(repoIDs, keyword, page, pageSize)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, nil, err
 | 
							return 0, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,9 +169,12 @@ repos = Repositories
 | 
				
			|||||||
users = Users
 | 
					users = Users
 | 
				
			||||||
organizations = Organizations
 | 
					organizations = Organizations
 | 
				
			||||||
search = Search
 | 
					search = Search
 | 
				
			||||||
 | 
					code = Code
 | 
				
			||||||
repo_no_results = No matching repositories have been found.
 | 
					repo_no_results = No matching repositories have been found.
 | 
				
			||||||
user_no_results = No matching users have been found.
 | 
					user_no_results = No matching users have been found.
 | 
				
			||||||
org_no_results = No matching organizations have been found.
 | 
					org_no_results = No matching organizations have been found.
 | 
				
			||||||
 | 
					code_no_results = No matching codes have been found.
 | 
				
			||||||
 | 
					code_search_results = Search results for "%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[auth]
 | 
					[auth]
 | 
				
			||||||
create_new_account = Create Account
 | 
					create_new_account = Create Account
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										116
									
								
								routers/home.go
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								routers/home.go
									
									
									
									
									
								
							@@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/search"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/routers/user"
 | 
						"code.gitea.io/gitea/routers/user"
 | 
				
			||||||
@@ -27,6 +28,8 @@ const (
 | 
				
			|||||||
	tplExploreUsers base.TplName = "explore/users"
 | 
						tplExploreUsers base.TplName = "explore/users"
 | 
				
			||||||
	// tplExploreOrganizations explore organizations page template
 | 
						// tplExploreOrganizations explore organizations page template
 | 
				
			||||||
	tplExploreOrganizations base.TplName = "explore/organizations"
 | 
						tplExploreOrganizations base.TplName = "explore/organizations"
 | 
				
			||||||
 | 
						// tplExploreCode explore code page template
 | 
				
			||||||
 | 
						tplExploreCode base.TplName = "explore/code"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Home render home page
 | 
					// Home render home page
 | 
				
			||||||
@@ -49,6 +52,7 @@ func Home(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["PageIsHome"] = true
 | 
						ctx.Data["PageIsHome"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.HTML(200, tplHome)
 | 
						ctx.HTML(200, tplHome)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,6 +128,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
				
			|||||||
	ctx.Data["Total"] = count
 | 
						ctx.Data["Total"] = count
 | 
				
			||||||
	ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, page, 5)
 | 
						ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, page, 5)
 | 
				
			||||||
	ctx.Data["Repos"] = repos
 | 
						ctx.Data["Repos"] = repos
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(200, opts.TplName)
 | 
						ctx.HTML(200, opts.TplName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -133,6 +138,7 @@ func ExploreRepos(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = ctx.Tr("explore")
 | 
						ctx.Data["Title"] = ctx.Tr("explore")
 | 
				
			||||||
	ctx.Data["PageIsExplore"] = true
 | 
						ctx.Data["PageIsExplore"] = true
 | 
				
			||||||
	ctx.Data["PageIsExploreRepositories"] = true
 | 
						ctx.Data["PageIsExploreRepositories"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var ownerID int64
 | 
						var ownerID int64
 | 
				
			||||||
	if ctx.User != nil && !ctx.User.IsAdmin {
 | 
						if ctx.User != nil && !ctx.User.IsAdmin {
 | 
				
			||||||
@@ -194,6 +200,7 @@ func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplN
 | 
				
			|||||||
	ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, opts.Page, 5)
 | 
						ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, opts.Page, 5)
 | 
				
			||||||
	ctx.Data["Users"] = users
 | 
						ctx.Data["Users"] = users
 | 
				
			||||||
	ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
 | 
						ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(200, tplName)
 | 
						ctx.HTML(200, tplName)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -203,6 +210,7 @@ func ExploreUsers(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = ctx.Tr("explore")
 | 
						ctx.Data["Title"] = ctx.Tr("explore")
 | 
				
			||||||
	ctx.Data["PageIsExplore"] = true
 | 
						ctx.Data["PageIsExplore"] = true
 | 
				
			||||||
	ctx.Data["PageIsExploreUsers"] = true
 | 
						ctx.Data["PageIsExploreUsers"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RenderUserSearch(ctx, &models.SearchUserOptions{
 | 
						RenderUserSearch(ctx, &models.SearchUserOptions{
 | 
				
			||||||
		Type:     models.UserTypeIndividual,
 | 
							Type:     models.UserTypeIndividual,
 | 
				
			||||||
@@ -216,6 +224,7 @@ func ExploreOrganizations(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["Title"] = ctx.Tr("explore")
 | 
						ctx.Data["Title"] = ctx.Tr("explore")
 | 
				
			||||||
	ctx.Data["PageIsExplore"] = true
 | 
						ctx.Data["PageIsExplore"] = true
 | 
				
			||||||
	ctx.Data["PageIsExploreOrganizations"] = true
 | 
						ctx.Data["PageIsExploreOrganizations"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RenderUserSearch(ctx, &models.SearchUserOptions{
 | 
						RenderUserSearch(ctx, &models.SearchUserOptions{
 | 
				
			||||||
		Type:     models.UserTypeOrganization,
 | 
							Type:     models.UserTypeOrganization,
 | 
				
			||||||
@@ -223,6 +232,113 @@ func ExploreOrganizations(ctx *context.Context) {
 | 
				
			|||||||
	}, tplExploreOrganizations)
 | 
						}, tplExploreOrganizations)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ExploreCode render explore code page
 | 
				
			||||||
 | 
					func ExploreCode(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !setting.Indexer.RepoIndexerEnabled {
 | 
				
			||||||
 | 
							ctx.Redirect("/explore", 302)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
						ctx.Data["Title"] = ctx.Tr("explore")
 | 
				
			||||||
 | 
						ctx.Data["PageIsExplore"] = true
 | 
				
			||||||
 | 
						ctx.Data["PageIsExploreCode"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyword := strings.TrimSpace(ctx.Query("q"))
 | 
				
			||||||
 | 
						page := ctx.QueryInt("page")
 | 
				
			||||||
 | 
						if page <= 0 {
 | 
				
			||||||
 | 
							page = 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							repoIDs []int64
 | 
				
			||||||
 | 
							err     error
 | 
				
			||||||
 | 
							isAdmin bool
 | 
				
			||||||
 | 
							userID  int64
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if ctx.User != nil {
 | 
				
			||||||
 | 
							userID = ctx.User.ID
 | 
				
			||||||
 | 
							isAdmin = ctx.User.IsAdmin
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// guest user or non-admin user
 | 
				
			||||||
 | 
						if ctx.User == nil || !isAdmin {
 | 
				
			||||||
 | 
							repoIDs, err = models.FindUserAccessibleRepoIDs(userID)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							total         int
 | 
				
			||||||
 | 
							searchResults []*search.Result
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if non-admin login user, we need check UnitTypeCode at first
 | 
				
			||||||
 | 
						if ctx.User != nil && len(repoIDs) > 0 {
 | 
				
			||||||
 | 
							repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
 | 
				
			||||||
 | 
							repoIDs = make([]int64, 0, len(repoMaps))
 | 
				
			||||||
 | 
							for id, repo := range repoMaps {
 | 
				
			||||||
 | 
								if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
 | 
				
			||||||
 | 
									rightRepoMap[id] = repo
 | 
				
			||||||
 | 
									repoIDs = append(repoIDs, id)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx.Data["RepoMaps"] = rightRepoMap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// if non-login user or isAdmin, no need to check UnitTypeCode
 | 
				
			||||||
 | 
						} else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
 | 
				
			||||||
 | 
							total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var loadRepoIDs = make([]int64, 0, len(searchResults))
 | 
				
			||||||
 | 
							for _, result := range searchResults {
 | 
				
			||||||
 | 
								var find bool
 | 
				
			||||||
 | 
								for _, id := range loadRepoIDs {
 | 
				
			||||||
 | 
									if id == result.RepoID {
 | 
				
			||||||
 | 
										find = true
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !find {
 | 
				
			||||||
 | 
									loadRepoIDs = append(loadRepoIDs, result.RepoID)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx.Data["RepoMaps"] = repoMaps
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["Keyword"] = keyword
 | 
				
			||||||
 | 
						pager := paginater.New(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
				
			||||||
 | 
						ctx.Data["Page"] = pager
 | 
				
			||||||
 | 
						ctx.Data["SearchResults"] = searchResults
 | 
				
			||||||
 | 
						ctx.Data["RequireHighlightJS"] = true
 | 
				
			||||||
 | 
						ctx.Data["PageIsViewCode"] = true
 | 
				
			||||||
 | 
						ctx.HTML(200, tplExploreCode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NotFound render 404 page
 | 
					// NotFound render 404 page
 | 
				
			||||||
func NotFound(ctx *context.Context) {
 | 
					func NotFound(ctx *context.Context) {
 | 
				
			||||||
	ctx.Data["Title"] = "Page Not Found"
 | 
						ctx.Data["Title"] = "Page Not Found"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,8 @@ func Search(ctx *context.Context) {
 | 
				
			|||||||
	if page <= 0 {
 | 
						if page <= 0 {
 | 
				
			||||||
		page = 1
 | 
							page = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	total, searchResults, err := search.PerformSearch(ctx.Repo.Repository.ID, keyword, page, setting.UI.RepoSearchPagingNum)
 | 
						total, searchResults, err := search.PerformSearch([]int64{ctx.Repo.Repository.ID},
 | 
				
			||||||
 | 
							keyword, page, setting.UI.RepoSearchPagingNum)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("SearchResults", err)
 | 
							ctx.ServerError("SearchResults", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -170,6 +170,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
		m.Get("/repos", routers.ExploreRepos)
 | 
							m.Get("/repos", routers.ExploreRepos)
 | 
				
			||||||
		m.Get("/users", routers.ExploreUsers)
 | 
							m.Get("/users", routers.ExploreUsers)
 | 
				
			||||||
		m.Get("/organizations", routers.ExploreOrganizations)
 | 
							m.Get("/organizations", routers.ExploreOrganizations)
 | 
				
			||||||
 | 
							m.Get("/code", routers.ExploreCode)
 | 
				
			||||||
	}, ignSignIn)
 | 
						}, ignSignIn)
 | 
				
			||||||
	m.Combo("/install", routers.InstallInit).Get(routers.Install).
 | 
						m.Combo("/install", routers.InstallInit).Get(routers.Install).
 | 
				
			||||||
		Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
 | 
							Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								templates/explore/code.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								templates/explore/code.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					{{template "base/head" .}}
 | 
				
			||||||
 | 
					<div class="explore users">
 | 
				
			||||||
 | 
						{{template "explore/navbar" .}}
 | 
				
			||||||
 | 
						<div class="ui container">
 | 
				
			||||||
 | 
							<form class="ui form" style="max-width: 100%">
 | 
				
			||||||
 | 
					            <div class="ui fluid action input">
 | 
				
			||||||
 | 
					                <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>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					        <div class="ui divider"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<div class="ui user list">
 | 
				
			||||||
 | 
								{{if .SearchResults}}
 | 
				
			||||||
 | 
					                <h3>
 | 
				
			||||||
 | 
					                    {{.i18n.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
 | 
				
			||||||
 | 
					                </h3>
 | 
				
			||||||
 | 
					                <div class="repository search">
 | 
				
			||||||
 | 
					                    {{range $result := .SearchResults}}
 | 
				
			||||||
 | 
					                        {{$repo := (index $.RepoMaps .RepoID)}}
 | 
				
			||||||
 | 
					                        <div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
 | 
				
			||||||
 | 
					                            <h4 class="ui top attached normal header">
 | 
				
			||||||
 | 
					                                <span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span>
 | 
				
			||||||
 | 
					                                <a class="ui basic grey tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/branch/{{$repo.DefaultBranch}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
 | 
				
			||||||
 | 
					                            </h4>
 | 
				
			||||||
 | 
					                            <div class="ui attached table segment">
 | 
				
			||||||
 | 
					                                <div class="file-body file-code code-view">
 | 
				
			||||||
 | 
					                                    <table>
 | 
				
			||||||
 | 
					                                        <tbody>
 | 
				
			||||||
 | 
					                                            <tr>
 | 
				
			||||||
 | 
					                                                <td class="lines-num">
 | 
				
			||||||
 | 
					                                                    {{range .LineNumbers}}
 | 
				
			||||||
 | 
					                                                        <a href="{{EscapePound $repo.HTMLURL}}/src/branch/{{$repo.DefaultBranch}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a>
 | 
				
			||||||
 | 
					                                                    {{end}}
 | 
				
			||||||
 | 
					                                                </td>
 | 
				
			||||||
 | 
					                                                <td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol class="linenums">{{.FormattedLines}}</ol></code></pre></td>
 | 
				
			||||||
 | 
					                                            </tr>
 | 
				
			||||||
 | 
					                                        </tbody>
 | 
				
			||||||
 | 
					                                    </table>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    {{end}}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
								{{else}}
 | 
				
			||||||
 | 
									<div>{{$.i18n.Tr "explore.code_no_results"}}</div>
 | 
				
			||||||
 | 
								{{end}}
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{{template "base/paginate" .}}
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{{template "base/footer" .}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -8,4 +8,9 @@
 | 
				
			|||||||
	<a class="{{if .PageIsExploreOrganizations}}active{{end}} item" href="{{AppSubUrl}}/explore/organizations">
 | 
						<a class="{{if .PageIsExploreOrganizations}}active{{end}} item" href="{{AppSubUrl}}/explore/organizations">
 | 
				
			||||||
		<span class="octicon octicon-organization"></span> {{.i18n.Tr "explore.organizations"}}
 | 
							<span class="octicon octicon-organization"></span> {{.i18n.Tr "explore.organizations"}}
 | 
				
			||||||
	</a>
 | 
						</a>
 | 
				
			||||||
 | 
						{{if .IsRepoIndexerEnabled}}
 | 
				
			||||||
 | 
						<a class="{{if .PageIsExploreCode}}active{{end}} item" href="{{AppSubUrl}}/explore/code">
 | 
				
			||||||
 | 
							<span class="octicon octicon-code"></span> {{.i18n.Tr "explore.code"}}
 | 
				
			||||||
 | 
						</a>
 | 
				
			||||||
 | 
						{{end}}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user