mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add user/organization code search (#19977)
Fixes #19925 Screenshots: 
This commit is contained in:
		@@ -593,6 +593,16 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
 | 
				
			|||||||
	return sess, count, nil
 | 
						return sess, count, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SearchRepositoryIDsByCondition search repository IDs by given condition.
 | 
				
			||||||
 | 
					func SearchRepositoryIDsByCondition(ctx context.Context, cond builder.Cond) ([]int64, error) {
 | 
				
			||||||
 | 
						repoIDs := make([]int64, 0, 10)
 | 
				
			||||||
 | 
						return repoIDs, db.GetEngine(ctx).
 | 
				
			||||||
 | 
							Table("repository").
 | 
				
			||||||
 | 
							Cols("id").
 | 
				
			||||||
 | 
							Where(cond).
 | 
				
			||||||
 | 
							Find(&repoIDs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
 | 
					// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
 | 
				
			||||||
func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond {
 | 
					func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond {
 | 
				
			||||||
	cond := builder.NewCond()
 | 
						cond := builder.NewCond()
 | 
				
			||||||
@@ -680,16 +690,16 @@ func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindUserCodeAccessibleRepoIDs finds all at Code level accessible repositories' ID by the user's id
 | 
					// FindUserCodeAccessibleRepoIDs finds all at Code level accessible repositories' ID by the user's id
 | 
				
			||||||
func FindUserCodeAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
 | 
					func FindUserCodeAccessibleRepoIDs(ctx context.Context, user *user_model.User) ([]int64, error) {
 | 
				
			||||||
	repoIDs := make([]int64, 0, 10)
 | 
						return SearchRepositoryIDsByCondition(ctx, AccessibleRepositoryCondition(user, unit.TypeCode))
 | 
				
			||||||
	if err := db.GetEngine(db.DefaultContext).
 | 
					}
 | 
				
			||||||
		Table("repository").
 | 
					
 | 
				
			||||||
		Cols("id").
 | 
					// FindUserCodeAccessibleOwnerRepoIDs finds all repository IDs for the given owner whose code the user can see.
 | 
				
			||||||
		Where(AccessibleRepositoryCondition(user, unit.TypeCode)).
 | 
					func FindUserCodeAccessibleOwnerRepoIDs(ctx context.Context, ownerID int64, user *user_model.User) ([]int64, error) {
 | 
				
			||||||
		Find(&repoIDs); err != nil {
 | 
						return SearchRepositoryIDsByCondition(ctx, builder.NewCond().And(
 | 
				
			||||||
		return nil, fmt.Errorf("FindUserCodeAccesibleRepoIDs: %v", err)
 | 
							builder.Eq{"owner_id": ownerID},
 | 
				
			||||||
	}
 | 
							AccessibleRepositoryCondition(user, unit.TypeCode),
 | 
				
			||||||
	return repoIDs, nil
 | 
						))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetUserRepositories returns a list of repositories of given user.
 | 
					// GetUserRepositories returns a list of repositories of given user.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,6 +130,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
 | 
				
			|||||||
	ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 | 
						ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
 | 
				
			||||||
	ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 | 
						ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
 | 
				
			||||||
	ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
						ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.Data["IsPublicMember"] = func(uid int64) bool {
 | 
						ctx.Data["IsPublicMember"] = func(uid int64) bool {
 | 
				
			||||||
		is, _ := organization.IsPublicMembership(ctx.Org.Organization.ID, uid)
 | 
							is, _ := organization.IsPublicMembership(ctx.Org.Organization.ID, uid)
 | 
				
			||||||
		return is
 | 
							return is
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -268,8 +268,11 @@ users = Users
 | 
				
			|||||||
organizations = Organizations
 | 
					organizations = Organizations
 | 
				
			||||||
search = Search
 | 
					search = Search
 | 
				
			||||||
code = Code
 | 
					code = Code
 | 
				
			||||||
 | 
					search.type.tooltip = Search type
 | 
				
			||||||
search.fuzzy = Fuzzy
 | 
					search.fuzzy = Fuzzy
 | 
				
			||||||
 | 
					search.fuzzy.tooltip = Include results that also matches the search term closely
 | 
				
			||||||
search.match = Match
 | 
					search.match = Match
 | 
				
			||||||
 | 
					search.match.tooltip = Include only results that matches the exact search term
 | 
				
			||||||
code_search_unavailable = Currently code search is not available. Please contact your site administrator.
 | 
					code_search_unavailable = Currently code search is not available. Please contact your site administrator.
 | 
				
			||||||
repo_no_results = No matching repositories found.
 | 
					repo_no_results = No matching repositories found.
 | 
				
			||||||
user_no_results = No matching users found.
 | 
					user_no_results = No matching users found.
 | 
				
			||||||
@@ -507,6 +510,7 @@ activity = Public Activity
 | 
				
			|||||||
followers = Followers
 | 
					followers = Followers
 | 
				
			||||||
starred = Starred Repositories
 | 
					starred = Starred Repositories
 | 
				
			||||||
watched = Watched Repositories
 | 
					watched = Watched Repositories
 | 
				
			||||||
 | 
					code = Code
 | 
				
			||||||
projects = Projects
 | 
					projects = Projects
 | 
				
			||||||
following = Following
 | 
					following = Following
 | 
				
			||||||
follow = Follow
 | 
					follow = Follow
 | 
				
			||||||
@@ -1763,8 +1767,11 @@ activity.git_stats_deletion_n = %d deletions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
search = Search
 | 
					search = Search
 | 
				
			||||||
search.search_repo = Search repository
 | 
					search.search_repo = Search repository
 | 
				
			||||||
 | 
					search.type.tooltip = Search type
 | 
				
			||||||
search.fuzzy = Fuzzy
 | 
					search.fuzzy = Fuzzy
 | 
				
			||||||
 | 
					search.fuzzy.tooltip = Include results that also matches the search term closely
 | 
				
			||||||
search.match = Match
 | 
					search.match = Match
 | 
				
			||||||
 | 
					search.match.tooltip = Include only results that matches the exact search term
 | 
				
			||||||
search.results = Search results for "%s" in <a href="%s">%s</a>
 | 
					search.results = Search results for "%s" in <a href="%s">%s</a>
 | 
				
			||||||
search.code_no_results = No source code matching your search term found.
 | 
					search.code_no_results = No source code matching your search term found.
 | 
				
			||||||
search.code_search_unavailable = Currently code search is not available. Please contact your site administrator.
 | 
					search.code_search_unavailable = Currently code search is not available. Please contact your site administrator.
 | 
				
			||||||
@@ -2310,6 +2317,7 @@ create_org = Create Organization
 | 
				
			|||||||
repo_updated = Updated
 | 
					repo_updated = Updated
 | 
				
			||||||
people = People
 | 
					people = People
 | 
				
			||||||
teams = Teams
 | 
					teams = Teams
 | 
				
			||||||
 | 
					code = Code
 | 
				
			||||||
lower_members = members
 | 
					lower_members = members
 | 
				
			||||||
lower_repositories = repositories
 | 
					lower_repositories = repositories
 | 
				
			||||||
create_new_team = New Team
 | 
					create_new_team = New Team
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,86 +34,91 @@ func Code(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	language := ctx.FormTrim("l")
 | 
						language := ctx.FormTrim("l")
 | 
				
			||||||
	keyword := ctx.FormTrim("q")
 | 
						keyword := ctx.FormTrim("q")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queryType := ctx.FormTrim("t")
 | 
				
			||||||
 | 
						isMatch := queryType == "match"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["Keyword"] = keyword
 | 
				
			||||||
 | 
						ctx.Data["Language"] = language
 | 
				
			||||||
 | 
						ctx.Data["queryType"] = queryType
 | 
				
			||||||
 | 
						ctx.Data["PageIsViewCode"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if keyword == "" {
 | 
				
			||||||
 | 
							ctx.HTML(http.StatusOK, tplExploreCode)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page := ctx.FormInt("page")
 | 
						page := ctx.FormInt("page")
 | 
				
			||||||
	if page <= 0 {
 | 
						if page <= 0 {
 | 
				
			||||||
		page = 1
 | 
							page = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	queryType := ctx.FormTrim("t")
 | 
						var (
 | 
				
			||||||
	isMatch := queryType == "match"
 | 
							repoIDs []int64
 | 
				
			||||||
 | 
							err     error
 | 
				
			||||||
	if keyword != "" {
 | 
							isAdmin bool
 | 
				
			||||||
		var (
 | 
						)
 | 
				
			||||||
			repoIDs []int64
 | 
						if ctx.Doer != nil {
 | 
				
			||||||
			err     error
 | 
							isAdmin = ctx.Doer.IsAdmin
 | 
				
			||||||
			isAdmin bool
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
		if ctx.Doer != nil {
 | 
					 | 
				
			||||||
			isAdmin = ctx.Doer.IsAdmin
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// guest user or non-admin user
 | 
					 | 
				
			||||||
		if ctx.Doer == nil || !isAdmin {
 | 
					 | 
				
			||||||
			repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx.Doer)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				ctx.ServerError("SearchResults", err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var (
 | 
					 | 
				
			||||||
			total                 int
 | 
					 | 
				
			||||||
			searchResults         []*code_indexer.Result
 | 
					 | 
				
			||||||
			searchResultLanguages []*code_indexer.SearchResultLanguages
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (len(repoIDs) > 0) || isAdmin {
 | 
					 | 
				
			||||||
			total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				if code_indexer.IsAvailable() {
 | 
					 | 
				
			||||||
					ctx.ServerError("SearchResults", err)
 | 
					 | 
				
			||||||
					return
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				ctx.Data["CodeIndexerUnavailable"] = true
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			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 := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				ctx.ServerError("SearchResults", err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ctx.Data["RepoMaps"] = repoMaps
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ctx.Data["Keyword"] = keyword
 | 
					 | 
				
			||||||
		ctx.Data["Language"] = language
 | 
					 | 
				
			||||||
		ctx.Data["queryType"] = queryType
 | 
					 | 
				
			||||||
		ctx.Data["SearchResults"] = searchResults
 | 
					 | 
				
			||||||
		ctx.Data["SearchResultLanguages"] = searchResultLanguages
 | 
					 | 
				
			||||||
		ctx.Data["PageIsViewCode"] = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
					 | 
				
			||||||
		pager.SetDefaultParams(ctx)
 | 
					 | 
				
			||||||
		pager.AddParam(ctx, "l", "Language")
 | 
					 | 
				
			||||||
		ctx.Data["Page"] = pager
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// guest user or non-admin user
 | 
				
			||||||
 | 
						if ctx.Doer == nil || !isAdmin {
 | 
				
			||||||
 | 
							repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx, ctx.Doer)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("FindUserCodeAccessibleRepoIDs", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							total                 int
 | 
				
			||||||
 | 
							searchResults         []*code_indexer.Result
 | 
				
			||||||
 | 
							searchResultLanguages []*code_indexer.SearchResultLanguages
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len(repoIDs) > 0) || isAdmin {
 | 
				
			||||||
 | 
							total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if code_indexer.IsAvailable() {
 | 
				
			||||||
 | 
									ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Data["CodeIndexerUnavailable"] = true
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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 := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("GetRepositoriesMapByIDs", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx.Data["RepoMaps"] = repoMaps
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["SearchResults"] = searchResults
 | 
				
			||||||
 | 
						ctx.Data["SearchResultLanguages"] = searchResultLanguages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
				
			||||||
 | 
						pager.SetDefaultParams(ctx)
 | 
				
			||||||
 | 
						pager.AddParam(ctx, "l", "Language")
 | 
				
			||||||
 | 
						ctx.Data["Page"] = pager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplExploreCode)
 | 
						ctx.HTML(http.StatusOK, tplExploreCode)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,14 +21,27 @@ func Search(ctx *context.Context) {
 | 
				
			|||||||
		ctx.Redirect(ctx.Repo.RepoLink)
 | 
							ctx.Redirect(ctx.Repo.RepoLink)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	language := ctx.FormTrim("l")
 | 
						language := ctx.FormTrim("l")
 | 
				
			||||||
	keyword := ctx.FormTrim("q")
 | 
						keyword := ctx.FormTrim("q")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queryType := ctx.FormTrim("t")
 | 
				
			||||||
 | 
						isMatch := queryType == "match"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["Keyword"] = keyword
 | 
				
			||||||
 | 
						ctx.Data["Language"] = language
 | 
				
			||||||
 | 
						ctx.Data["queryType"] = queryType
 | 
				
			||||||
 | 
						ctx.Data["PageIsViewCode"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if keyword == "" {
 | 
				
			||||||
 | 
							ctx.HTML(http.StatusOK, tplSearch)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page := ctx.FormInt("page")
 | 
						page := ctx.FormInt("page")
 | 
				
			||||||
	if page <= 0 {
 | 
						if page <= 0 {
 | 
				
			||||||
		page = 1
 | 
							page = 1
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	queryType := ctx.FormTrim("t")
 | 
					 | 
				
			||||||
	isMatch := queryType == "match"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	total, searchResults, searchResultLanguages, err := code_indexer.PerformSearch(ctx, []int64{ctx.Repo.Repository.ID},
 | 
						total, searchResults, searchResultLanguages, err := code_indexer.PerformSearch(ctx, []int64{ctx.Repo.Repository.ID},
 | 
				
			||||||
		language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
 | 
							language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
 | 
				
			||||||
@@ -41,13 +54,10 @@ func Search(ctx *context.Context) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
 | 
							ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["Keyword"] = keyword
 | 
					
 | 
				
			||||||
	ctx.Data["Language"] = language
 | 
					 | 
				
			||||||
	ctx.Data["queryType"] = queryType
 | 
					 | 
				
			||||||
	ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
 | 
						ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
 | 
				
			||||||
	ctx.Data["SearchResults"] = searchResults
 | 
						ctx.Data["SearchResults"] = searchResults
 | 
				
			||||||
	ctx.Data["SearchResultLanguages"] = searchResultLanguages
 | 
						ctx.Data["SearchResultLanguages"] = searchResultLanguages
 | 
				
			||||||
	ctx.Data["PageIsViewCode"] = true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
						pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
				
			||||||
	pager.SetDefaultParams(ctx)
 | 
						pager.SetDefaultParams(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										114
									
								
								routers/web/user/code.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								routers/web/user/code.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
 | 
						code_indexer "code.gitea.io/gitea/modules/indexer/code"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						tplUserCode base.TplName = "user/code"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CodeSearch render user/organization code search page
 | 
				
			||||||
 | 
					func CodeSearch(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !setting.Indexer.RepoIndexerEnabled {
 | 
				
			||||||
 | 
							ctx.Redirect(ctx.ContextUser.HomeLink())
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
						ctx.Data["Title"] = ctx.Tr("code.title")
 | 
				
			||||||
 | 
						ctx.Data["ContextUser"] = ctx.ContextUser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						language := ctx.FormTrim("l")
 | 
				
			||||||
 | 
						keyword := ctx.FormTrim("q")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queryType := ctx.FormTrim("t")
 | 
				
			||||||
 | 
						isMatch := queryType == "match"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["Keyword"] = keyword
 | 
				
			||||||
 | 
						ctx.Data["Language"] = language
 | 
				
			||||||
 | 
						ctx.Data["queryType"] = queryType
 | 
				
			||||||
 | 
						ctx.Data["IsCodePage"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if keyword == "" {
 | 
				
			||||||
 | 
							ctx.HTML(http.StatusOK, tplUserCode)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							repoIDs []int64
 | 
				
			||||||
 | 
							err     error
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page := ctx.FormInt("page")
 | 
				
			||||||
 | 
						if page <= 0 {
 | 
				
			||||||
 | 
							page = 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repoIDs, err = repo_model.FindUserCodeAccessibleOwnerRepoIDs(ctx, ctx.ContextUser.ID, ctx.Doer)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("FindUserCodeAccessibleOwnerRepoIDs", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							total                 int
 | 
				
			||||||
 | 
							searchResults         []*code_indexer.Result
 | 
				
			||||||
 | 
							searchResultLanguages []*code_indexer.SearchResultLanguages
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(repoIDs) > 0 {
 | 
				
			||||||
 | 
							total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if code_indexer.IsAvailable() {
 | 
				
			||||||
 | 
									ctx.ServerError("SearchResults", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Data["CodeIndexerUnavailable"] = true
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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 := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								ctx.ServerError("GetRepositoriesMapByIDs", err)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ctx.Data["RepoMaps"] = repoMaps
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["SearchResults"] = searchResults
 | 
				
			||||||
 | 
						ctx.Data["SearchResultLanguages"] = searchResultLanguages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
 | 
				
			||||||
 | 
						pager.SetDefaultParams(ctx)
 | 
				
			||||||
 | 
						pager.AddParam(ctx, "l", "Language")
 | 
				
			||||||
 | 
						ctx.Data["Page"] = pager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.HTML(http.StatusOK, tplUserCode)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -86,6 +86,7 @@ func ListPackages(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("packages.title")
 | 
						ctx.Data["Title"] = ctx.Tr("packages.title")
 | 
				
			||||||
	ctx.Data["IsPackagesPage"] = true
 | 
						ctx.Data["IsPackagesPage"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctx.ContextUser
 | 
						ctx.Data["ContextUser"] = ctx.ContextUser
 | 
				
			||||||
	ctx.Data["Query"] = query
 | 
						ctx.Data["Query"] = query
 | 
				
			||||||
	ctx.Data["PackageType"] = packageType
 | 
						ctx.Data["PackageType"] = packageType
 | 
				
			||||||
@@ -157,6 +158,7 @@ func ViewPackageVersion(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["Title"] = pd.Package.Name
 | 
						ctx.Data["Title"] = pd.Package.Name
 | 
				
			||||||
	ctx.Data["IsPackagesPage"] = true
 | 
						ctx.Data["IsPackagesPage"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctx.ContextUser
 | 
						ctx.Data["ContextUser"] = ctx.ContextUser
 | 
				
			||||||
	ctx.Data["PackageDescriptor"] = pd
 | 
						ctx.Data["PackageDescriptor"] = pd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,6 +236,7 @@ func ListPackageVersions(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["Title"] = ctx.Tr("packages.title")
 | 
						ctx.Data["Title"] = ctx.Tr("packages.title")
 | 
				
			||||||
	ctx.Data["IsPackagesPage"] = true
 | 
						ctx.Data["IsPackagesPage"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctx.ContextUser
 | 
						ctx.Data["ContextUser"] = ctx.ContextUser
 | 
				
			||||||
	ctx.Data["PackageDescriptor"] = &packages_model.PackageDescriptor{
 | 
						ctx.Data["PackageDescriptor"] = &packages_model.PackageDescriptor{
 | 
				
			||||||
		Package: p,
 | 
							Package: p,
 | 
				
			||||||
@@ -305,6 +308,7 @@ func PackageSettings(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["Title"] = pd.Package.Name
 | 
						ctx.Data["Title"] = pd.Package.Name
 | 
				
			||||||
	ctx.Data["IsPackagesPage"] = true
 | 
						ctx.Data["IsPackagesPage"] = true
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctx.ContextUser
 | 
						ctx.Data["ContextUser"] = ctx.ContextUser
 | 
				
			||||||
	ctx.Data["PackageDescriptor"] = pd
 | 
						ctx.Data["PackageDescriptor"] = pd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -290,6 +290,7 @@ func Profile(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["Page"] = pager
 | 
						ctx.Data["Page"] = pager
 | 
				
			||||||
	ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
						ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
 | 
				
			||||||
 | 
						ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["ShowUserEmail"] = len(ctx.ContextUser.Email) > 0 && ctx.IsSigned && (!ctx.ContextUser.KeepEmailPrivate || ctx.ContextUser.ID == ctx.Doer.ID)
 | 
						ctx.Data["ShowUserEmail"] = len(ctx.ContextUser.Email) > 0 && ctx.IsSigned && (!ctx.ContextUser.KeepEmailPrivate || ctx.ContextUser.ID == ctx.Doer.ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -754,6 +754,7 @@ func RegisterRoutes(m *web.Route) {
 | 
				
			|||||||
				})
 | 
									})
 | 
				
			||||||
			}, ignSignIn, context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
 | 
								}, ignSignIn, context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							m.Get("/code", user.CodeSearch)
 | 
				
			||||||
	}, context_service.UserAssignmentWeb())
 | 
						}, context_service.UserAssignmentWeb())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ***** Release Attachment Download without Signin
 | 
						// ***** Release Attachment Download without Signin
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								templates/code/searchform.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								templates/code/searchform.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					<form class="ui form ignore-dirty" style="max-width: 100%">
 | 
				
			||||||
 | 
						<div class="ui fluid action input">
 | 
				
			||||||
 | 
							<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable }} disabled{{end}} placeholder="{{.locale.Tr "explore.search"}}…" autofocus>
 | 
				
			||||||
 | 
							<div class="ui dropdown selection tooltip{{if .CodeIndexerUnavailable }} disabled{{end}}" data-content="{{.locale.Tr "explore.search.type.tooltip"}}">
 | 
				
			||||||
 | 
								<input name="t" type="hidden" value="{{.queryType}}"{{if .CodeIndexerUnavailable }} disabled{{end}}>{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 | 
				
			||||||
 | 
								<div class="text">{{.locale.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
 | 
				
			||||||
 | 
								<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
 | 
				
			||||||
 | 
									<div class="item tooltip" data-value="" data-content="{{.locale.Tr "explore.search.fuzzy.tooltip"}}">{{.locale.Tr "explore.search.fuzzy"}}</div>
 | 
				
			||||||
 | 
									<div class="item tooltip" data-value="match" data-content="{{.locale.Tr "explore.search.match.tooltip"}}">{{.locale.Tr "explore.search.match"}}</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<button class="ui primary button"{{if .CodeIndexerUnavailable }} disabled{{end}}>{{.locale.Tr "explore.search"}}</button>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
							
								
								
									
										43
									
								
								templates/code/searchresults.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								templates/code/searchresults.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					<div class="df ac fw">
 | 
				
			||||||
 | 
						{{range $term := .SearchResultLanguages}}
 | 
				
			||||||
 | 
						<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}{{if $.ContextUser}}/{{$.ContextUser.Name}}/-/code{{else}}/explore/code{{end}}?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
 | 
				
			||||||
 | 
							<i class="color-icon mr-3" style="background-color: {{$term.Color}}"></i>
 | 
				
			||||||
 | 
							{{$term.Language}}
 | 
				
			||||||
 | 
							<div class="detail">{{$term.Count}}</div>
 | 
				
			||||||
 | 
						</a>
 | 
				
			||||||
 | 
						{{end}}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<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="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
 | 
				
			||||||
 | 
											{{if $repo.IsArchived}}
 | 
				
			||||||
 | 
												<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
 | 
				
			||||||
 | 
											{{end}}
 | 
				
			||||||
 | 
										- {{.Filename}}
 | 
				
			||||||
 | 
									</span>
 | 
				
			||||||
 | 
									<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.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="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
 | 
				
			||||||
 | 
														{{end}}
 | 
				
			||||||
 | 
													</td>
 | 
				
			||||||
 | 
													<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>
 | 
				
			||||||
 | 
												</tr>
 | 
				
			||||||
 | 
											</tbody>
 | 
				
			||||||
 | 
										</table>
 | 
				
			||||||
 | 
									</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
								{{template "shared/searchbottom" dict "root" $ "result" .}}
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						{{end}}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -2,20 +2,7 @@
 | 
				
			|||||||
<div class="page-content explore users">
 | 
					<div class="page-content explore users">
 | 
				
			||||||
	{{template "explore/navbar" .}}
 | 
						{{template "explore/navbar" .}}
 | 
				
			||||||
	<div class="ui container">
 | 
						<div class="ui container">
 | 
				
			||||||
		<form class="ui form ignore-dirty" style="max-width: 100%">
 | 
							{{template "code/searchform" .}}
 | 
				
			||||||
			<div class="ui fluid action input">
 | 
					 | 
				
			||||||
				<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable}} disabled{{end}} placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
 | 
					 | 
				
			||||||
				<div class="ui dropdown selection{{if .CodeIndexerUnavailable}} disabled{{end}}">
 | 
					 | 
				
			||||||
					<input name="t" type="hidden" value="{{.queryType}}"{{if .CodeIndexerUnavailable}} disabled{{end}}>{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 | 
					 | 
				
			||||||
					<div class="text">{{.locale.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
 | 
					 | 
				
			||||||
					<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
 | 
					 | 
				
			||||||
						<div class="item" data-value="">{{.locale.Tr "explore.search.fuzzy"}}</div>
 | 
					 | 
				
			||||||
						<div class="item" data-value="match">{{.locale.Tr "explore.search.match"}}</div>
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
				<button class="ui primary button"{{if .CodeIndexerUnavailable}} disabled{{end}}>{{.locale.Tr "explore.search"}}</button>
 | 
					 | 
				
			||||||
			</div>
 | 
					 | 
				
			||||||
		</form>
 | 
					 | 
				
			||||||
		<div class="ui divider"></div>
 | 
							<div class="ui divider"></div>
 | 
				
			||||||
		<div class="ui user list">
 | 
							<div class="ui user list">
 | 
				
			||||||
			{{if .CodeIndexerUnavailable}}
 | 
								{{if .CodeIndexerUnavailable}}
 | 
				
			||||||
@@ -26,50 +13,8 @@
 | 
				
			|||||||
				<h3>
 | 
									<h3>
 | 
				
			||||||
					{{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}}
 | 
										{{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}}
 | 
				
			||||||
				</h3>
 | 
									</h3>
 | 
				
			||||||
				<div class="df ac fw">
 | 
									{{template "code/searchresults" .}}
 | 
				
			||||||
					{{range $term := .SearchResultLanguages}}
 | 
								{{else if .Keyword}}
 | 
				
			||||||
					<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
 | 
					 | 
				
			||||||
						<i class="color-icon mr-3" style="background-color: {{$term.Color}}"></i>
 | 
					 | 
				
			||||||
						{{$term.Language}}
 | 
					 | 
				
			||||||
						<div class="detail">{{$term.Count}}</div>
 | 
					 | 
				
			||||||
					</a>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
				<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="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
 | 
					 | 
				
			||||||
										{{if $repo.IsArchived}}
 | 
					 | 
				
			||||||
											<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
 | 
					 | 
				
			||||||
										{{end}}
 | 
					 | 
				
			||||||
									- {{.Filename}}
 | 
					 | 
				
			||||||
								</span>
 | 
					 | 
				
			||||||
								<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.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="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
 | 
					 | 
				
			||||||
													{{end}}
 | 
					 | 
				
			||||||
												</td>
 | 
					 | 
				
			||||||
												<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>
 | 
					 | 
				
			||||||
											</tr>
 | 
					 | 
				
			||||||
										</tbody>
 | 
					 | 
				
			||||||
									</table>
 | 
					 | 
				
			||||||
								</div>
 | 
					 | 
				
			||||||
							</div>
 | 
					 | 
				
			||||||
							{{template "shared/searchbottom" dict "root" $ "result" .}}
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
			{{else}}
 | 
					 | 
				
			||||||
				<div>{{$.locale.Tr "explore.code_no_results"}}</div>
 | 
									<div>{{$.locale.Tr "explore.code_no_results"}}</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@
 | 
				
			|||||||
	<input type="hidden" name="sort" value="{{$.SortType}}">
 | 
						<input type="hidden" name="sort" value="{{$.SortType}}">
 | 
				
			||||||
	<input type="hidden" name="language" value="{{$.Language}}">
 | 
						<input type="hidden" name="language" value="{{$.Language}}">
 | 
				
			||||||
	<div class="ui fluid action input">
 | 
						<div class="ui fluid action input">
 | 
				
			||||||
		<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
 | 
							<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}…" autofocus>
 | 
				
			||||||
		<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
 | 
							<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
<form class="ui form ignore-dirty" style="max-width: 90%">
 | 
					<form class="ui form ignore-dirty" style="max-width: 90%">
 | 
				
			||||||
	<div class="ui fluid action input">
 | 
						<div class="ui fluid action input">
 | 
				
			||||||
		<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
 | 
							<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}…" autofocus>
 | 
				
			||||||
		<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
 | 
							<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<div class="ui tabs container">
 | 
					<div class="ui tabs container">
 | 
				
			||||||
	<div class="ui secondary stackable pointing menu">
 | 
						<div class="ui secondary stackable pointing menu">
 | 
				
			||||||
		<a class="{{if .PageIsViewRepositories}}active{{end}} item" href="{{$.Org.HomeLink}}">
 | 
							<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}">
 | 
				
			||||||
			{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
								{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
				
			||||||
		</a>
 | 
							</a>
 | 
				
			||||||
		{{if .IsPackageEnabled}}
 | 
							{{if .IsPackageEnabled}}
 | 
				
			||||||
@@ -8,14 +8,19 @@
 | 
				
			|||||||
			{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
								{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
				
			||||||
		</a>
 | 
							</a>
 | 
				
			||||||
		{{end}}
 | 
							{{end}}
 | 
				
			||||||
 | 
							{{if .IsRepoIndexerEnabled}}
 | 
				
			||||||
 | 
							<a class="{{if $.PageIsOrgCode}}active {{end}}item" href="{{$.Org.HomeLink}}/-/code">
 | 
				
			||||||
 | 
								{{svg "octicon-code"}} {{$.locale.Tr "org.code"}}
 | 
				
			||||||
 | 
							</a>
 | 
				
			||||||
 | 
							{{end}}
 | 
				
			||||||
		{{if .IsOrganizationMember}}
 | 
							{{if .IsOrganizationMember}}
 | 
				
			||||||
			<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
 | 
								<a class="{{if $.PageIsOrgMembers}}active {{end}}item" href="{{$.OrgLink}}/members">
 | 
				
			||||||
				{{svg "octicon-organization"}} {{$.locale.Tr "org.people"}}
 | 
									{{svg "octicon-organization"}} {{$.locale.Tr "org.people"}}
 | 
				
			||||||
				{{if .NumMembers}}
 | 
									{{if .NumMembers}}
 | 
				
			||||||
					<div class="ui primary label">{{.NumMembers}}</div>
 | 
										<div class="ui primary label">{{.NumMembers}}</div>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
			</a>
 | 
								</a>
 | 
				
			||||||
			<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams">
 | 
								<a class="{{if $.PageIsOrgTeams}}active {{end}}item" href="{{$.OrgLink}}/teams">
 | 
				
			||||||
				{{svg "octicon-people"}} {{$.locale.Tr "org.teams"}}
 | 
									{{svg "octicon-people"}} {{$.locale.Tr "org.teams"}}
 | 
				
			||||||
				{{if .NumTeams}}
 | 
									{{if .NumTeams}}
 | 
				
			||||||
					<div class="ui primary label">{{.NumTeams}}</div>
 | 
										<div class="ui primary label">{{.NumTeams}}</div>
 | 
				
			||||||
@@ -25,7 +30,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		{{if .IsOrganizationOwner}}
 | 
							{{if .IsOrganizationOwner}}
 | 
				
			||||||
			<div class="right menu">
 | 
								<div class="right menu">
 | 
				
			||||||
				<a class="{{if .PageIsOrgSettings}}active{{end}} item" href="{{.OrgLink}}/settings">
 | 
									<a class="{{if .PageIsOrgSettings}}active {{end}}item" href="{{.OrgLink}}/settings">
 | 
				
			||||||
				{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
 | 
									{{svg "octicon-tools"}} {{.locale.Tr "repo.settings"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,12 +6,12 @@
 | 
				
			|||||||
			<form class="ui form ignore-dirty" method="get">
 | 
								<form class="ui form ignore-dirty" method="get">
 | 
				
			||||||
				<div class="ui fluid action input">
 | 
									<div class="ui fluid action input">
 | 
				
			||||||
					<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable}} disabled{{end}} placeholder="{{.locale.Tr "repo.search.search_repo"}}">
 | 
										<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable}} disabled{{end}} placeholder="{{.locale.Tr "repo.search.search_repo"}}">
 | 
				
			||||||
					<div class="ui dropdown selection{{if .CodeIndexerUnavailable}} disabled{{end}}">
 | 
										<div class="ui dropdown selection tooltip{{if .CodeIndexerUnavailable}} disabled{{end}}" data-content="{{.locale.Tr "repo.search.type.tooltip"}}">
 | 
				
			||||||
						<input name="t" type="hidden"{{if .CodeIndexerUnavailable}} disabled{{end}} value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 | 
											<input name="t" type="hidden"{{if .CodeIndexerUnavailable}} disabled{{end}} value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 | 
				
			||||||
						<div class="text">{{.locale.Tr (printf "repo.search.%s" (or .queryType "fuzzy"))}}</div>
 | 
											<div class="text">{{.locale.Tr (printf "repo.search.%s" (or .queryType "fuzzy"))}}</div>
 | 
				
			||||||
						<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
 | 
											<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
 | 
				
			||||||
							<div class="item" data-value="">{{.locale.Tr "repo.search.fuzzy"}}</div>
 | 
												<div class="item tooltip" data-value="" data-content="{{.locale.Tr "repo.search.fuzzy.tooltip"}}">{{.locale.Tr "repo.search.fuzzy"}}</div>
 | 
				
			||||||
							<div class="item" data-value="match">{{.locale.Tr "repo.search.match"}}</div>
 | 
												<div class="item tooltip" data-value="match" data-content="{{.locale.Tr "repo.search.match.tooltip"}}">{{.locale.Tr "repo.search.match"}}</div>
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<button class="ui icon button"{{if .CodeIndexerUnavailable}} disabled{{end}} type="submit">{{svg "octicon-search" 16}}</button>
 | 
										<button class="ui icon button"{{if .CodeIndexerUnavailable}} disabled{{end}} type="submit">{{svg "octicon-search" 16}}</button>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								templates/user/code.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								templates/user/code.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					{{template "base/head" .}}
 | 
				
			||||||
 | 
					<div class="page-content repository code-search">
 | 
				
			||||||
 | 
						{{template "user/overview/header" .}}
 | 
				
			||||||
 | 
						<div class="ui container">
 | 
				
			||||||
 | 
							{{template "code/searchform" .}}
 | 
				
			||||||
 | 
							<div class="ui divider"></div>
 | 
				
			||||||
 | 
							<div class="ui user list">
 | 
				
			||||||
 | 
								{{if .CodeIndexerUnavailable }}
 | 
				
			||||||
 | 
									<div class="ui error message">
 | 
				
			||||||
 | 
										<p>{{$.locale.Tr "explore.code_search_unavailable"}}</p>
 | 
				
			||||||
 | 
									</div>
 | 
				
			||||||
 | 
								{{else if .SearchResults}}
 | 
				
			||||||
 | 
									<h3>
 | 
				
			||||||
 | 
										{{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html }}
 | 
				
			||||||
 | 
									</h3>
 | 
				
			||||||
 | 
									{{template "code/searchresults" .}}
 | 
				
			||||||
 | 
								{{else if .Keyword}}
 | 
				
			||||||
 | 
									<div>{{$.locale.Tr "explore.code_no_results"}}</div>
 | 
				
			||||||
 | 
								{{end}}
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{{template "base/paginate" .}}
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{{template "base/footer" .}}
 | 
				
			||||||
@@ -23,10 +23,15 @@
 | 
				
			|||||||
				{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
									{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
				
			||||||
			</a>
 | 
								</a>
 | 
				
			||||||
			{{if (not .UnitPackagesGlobalDisabled)}}
 | 
								{{if (not .UnitPackagesGlobalDisabled)}}
 | 
				
			||||||
				<a href="{{.ContextUser.HTMLURL}}/-/packages" class="{{if .IsPackagesPage}}active{{end}} item">
 | 
									<a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item">
 | 
				
			||||||
					{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
										{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
 | 
								{{if .IsRepoIndexerEnabled}}
 | 
				
			||||||
 | 
									<a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item">
 | 
				
			||||||
 | 
										{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
 | 
				
			||||||
 | 
									</a>
 | 
				
			||||||
 | 
								{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{{if .ContextUser.IsOrganization}}
 | 
								{{if .ContextUser.IsOrganization}}
 | 
				
			||||||
				{{if .IsOrganizationMember}}
 | 
									{{if .IsOrganizationMember}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,7 +101,7 @@
 | 
				
			|||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<div class="ui eleven wide column">
 | 
								<div class="ui eleven wide column">
 | 
				
			||||||
				<div class="ui secondary stackable pointing tight menu">
 | 
									<div class="ui secondary stackable pointing tight menu">
 | 
				
			||||||
					<a class='{{if and (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars") (ne .TabName "watching") (ne .TabName "projects")}}active{{end}} item' href="{{.Owner.HomeLink}}">
 | 
										<a class='{{if and (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars") (ne .TabName "watching") (ne .TabName "projects") (ne .TabName "code")}}active{{end}} item' href="{{.Owner.HomeLink}}">
 | 
				
			||||||
						{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
											{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
					{{if .IsPackageEnabled}}
 | 
										{{if .IsPackageEnabled}}
 | 
				
			||||||
@@ -109,6 +109,11 @@
 | 
				
			|||||||
						{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
											{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
 | 
										{{if .IsRepoIndexerEnabled}}
 | 
				
			||||||
 | 
										<a class='{{if eq .TabName "code"}}active{{end}} item' href="{{.Owner.HomeLink}}/-/code">
 | 
				
			||||||
 | 
											{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
 | 
				
			||||||
 | 
										</a>
 | 
				
			||||||
 | 
										{{end}}
 | 
				
			||||||
					<a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity">
 | 
										<a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity">
 | 
				
			||||||
						{{svg "octicon-rss"}} {{.locale.Tr "user.activity"}}
 | 
											{{svg "octicon-rss"}} {{.locale.Tr "user.activity"}}
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user