From dfe0ce8de0b23cf8d49b08eac731455624a21579 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 24 Jul 2025 08:30:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- routers/hat/hat.go | 4 ++ routers/hat/repo/explore/code.go | 119 +++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 routers/hat/repo/explore/code.go diff --git a/routers/hat/hat.go b/routers/hat/hat.go index c265181..7a3d7dc 100644 --- a/routers/hat/hat.go +++ b/routers/hat/hat.go @@ -30,6 +30,7 @@ import ( "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/org" "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo" "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo/actions" + "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo/explore" "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/user" "github.com/go-chi/cors" ) @@ -125,6 +126,9 @@ func Routers() *web.Route { m.Post("/update_hook_arm", bind(gitea_api.RepositoryPayload{}), repo.UpdateHookArm) m.Post("/update_repo_size_limit_hook", bind(gitea_api.RepositoryPayload{}), repo.UpdateRepoSizeLimitHook) m.Group("/repos", func() { + if setting.Indexer.RepoIndexerEnabled { + m.Get("/explore/code", explore.Code) + } m.Group("/{username}/{reponame}", func() { m.Combo("").Delete(reqToken(), reqOwner(), repo.Delete) m.Group("/actions", func() { diff --git a/routers/hat/repo/explore/code.go b/routers/hat/repo/explore/code.go new file mode 100644 index 0000000..b3f3089 --- /dev/null +++ b/routers/hat/repo/explore/code.go @@ -0,0 +1,119 @@ +package explore + +import ( + "fmt" + "math" + "net/http" + "strconv" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + code_indexer "code.gitea.io/gitea/modules/indexer/code" + "code.gitea.io/gitea/modules/setting" +) + +func Code(ctx *context.APIContext) { + language := ctx.FormString("language") + keyword := ctx.FormString("keyword") + queryType := ctx.FormString("query_type") + isMatch := queryType == "match" + + page := ctx.FormInt("page") + if page <= 0 { + page = 1 + } + + var ( + repoIDs []int64 + err error + isAdmin bool + ) + + if ctx.Doer != nil { + isAdmin = ctx.Doer.IsAdmin + } + + if ctx.Doer == nil || !isAdmin { + repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx, ctx.Doer) + if err != nil { + ctx.Error(http.StatusInternalServerError, "FindUserCodeAccessibleRepoIDs", err) + return + } + } + + var ( + total int + searchResults []*code_indexer.Result + searchResultLanguages []*code_indexer.SearchResultLanguages + ) + + var codeIndexerUnavailable bool + var repoMaps map[int64]*repo_model.Repository + 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) { + ctx.Error(http.StatusInternalServerError, "SearchResults", err) + return + } + codeIndexerUnavailable = true + } else { + codeIndexerUnavailable = !code_indexer.IsAvailable(ctx) + } + + 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.Error(http.StatusInternalServerError, "GetRepositoriesMapByIDs", err) + return + } + + repoMaps = repoMaps + + if len(loadRepoIDs) != len(repoMaps) { + // Remove deleted repos from search results + cleanedSearchResults := make([]*code_indexer.Result, 0, len(repoMaps)) + for _, sr := range searchResults { + if _, found := repoMaps[sr.RepoID]; found { + cleanedSearchResults = append(cleanedSearchResults, sr) + } + } + + searchResults = cleanedSearchResults + } + } + + pageCount := int(math.Ceil(float64(total) / float64(setting.UI.RepoSearchPagingNum))) + ctx.Resp.Header().Set("X-Page", strconv.Itoa(page)) + ctx.Resp.Header().Set("X-PerPage", strconv.Itoa(setting.UI.RepoSearchPagingNum)) + ctx.Resp.Header().Set("X-Total", strconv.FormatInt(int64(total), 10)) + ctx.Resp.Header().Set("X-PageCount", strconv.Itoa(pageCount)) + ctx.Resp.Header().Set("X-HasMore", strconv.FormatBool(page < pageCount)) + + ctx.SetLinkHeader(int(total), setting.UI.RepoSearchPagingNum) + ctx.Resp.Header().Set("X-Total-Count", fmt.Sprintf("%d", total)) + ctx.JSON(http.StatusOK, struct { + CodeIndexerUnavailable bool + RepoMaps map[int64]*repo_model.Repository + SearchResults []*code_indexer.Result + SearchResultLanguages []*code_indexer.SearchResultLanguages + }{ + CodeIndexerUnavailable: codeIndexerUnavailable, + RepoMaps: repoMaps, + SearchResults: searchResults, + SearchResultLanguages: searchResultLanguages, + }) +}