|
|
@@ -0,0 +1,1190 @@ |
|
|
|
package routers |
|
|
|
|
|
|
|
import ( |
|
|
|
"encoding/json" |
|
|
|
"fmt" |
|
|
|
"sort" |
|
|
|
"strconv" |
|
|
|
"strings" |
|
|
|
|
|
|
|
"code.gitea.io/gitea/models" |
|
|
|
"code.gitea.io/gitea/modules/context" |
|
|
|
"code.gitea.io/gitea/modules/log" |
|
|
|
"code.gitea.io/gitea/modules/setting" |
|
|
|
"code.gitea.io/gitea/modules/timeutil" |
|
|
|
"github.com/olivere/elastic/v7" |
|
|
|
) |
|
|
|
|
|
|
|
type SearchRes struct { |
|
|
|
Total int64 |
|
|
|
Result []map[string]interface{} |
|
|
|
PrivateTotal int64 |
|
|
|
} |
|
|
|
|
|
|
|
var client *elastic.Client |
|
|
|
|
|
|
|
func InitESClient() { |
|
|
|
ESSearchUrl := setting.ESSearchURL |
|
|
|
var err error |
|
|
|
client, err = elastic.NewClient(elastic.SetSniff(false), elastic.SetURL(ESSearchUrl)) |
|
|
|
if err != nil { |
|
|
|
log.Info("es init error.") |
|
|
|
//panic(err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func EmptySearch(ctx *context.Context) { |
|
|
|
log.Info("search template.") |
|
|
|
ctx.Data["Keyword"] = "" |
|
|
|
ctx.HTML(200, "explore/search_new") |
|
|
|
} |
|
|
|
|
|
|
|
func Search(ctx *context.Context) { |
|
|
|
log.Info("search template.") |
|
|
|
keyword := strings.Trim(ctx.Query("q"), " ") |
|
|
|
ctx.Data["Keyword"] = keyword |
|
|
|
ctx.Data["SortType"] = "newest" |
|
|
|
ctx.HTML(200, "explore/search_new") |
|
|
|
} |
|
|
|
|
|
|
|
func SearchApi(ctx *context.Context) { |
|
|
|
TableName := ctx.Query("TableName") |
|
|
|
Key := ctx.Query("Key") |
|
|
|
Page := ctx.QueryInt("Page") |
|
|
|
PageSize := ctx.QueryInt("PageSize") |
|
|
|
OnlyReturnNum := ctx.QueryBool("OnlyReturnNum") |
|
|
|
OnlySearchLabel := ctx.QueryBool("OnlySearchLabel") |
|
|
|
|
|
|
|
if Page <= 0 { |
|
|
|
Page = 1 |
|
|
|
} |
|
|
|
if PageSize <= 0 || PageSize > 200 { |
|
|
|
PageSize = setting.UI.IssuePagingNum |
|
|
|
} |
|
|
|
if Key != "" && !OnlyReturnNum { |
|
|
|
go models.SaveSearchKeywordToDb(Key) |
|
|
|
} |
|
|
|
if TableName == "repository" { |
|
|
|
if OnlySearchLabel { |
|
|
|
searchRepoByLabel(ctx, Key, Page, PageSize) |
|
|
|
} else { |
|
|
|
searchRepo(ctx, "repository-es-index", Key, Page, PageSize, OnlyReturnNum) |
|
|
|
} |
|
|
|
return |
|
|
|
} else if TableName == "issue" { |
|
|
|
searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "f") |
|
|
|
return |
|
|
|
} else if TableName == "user" { |
|
|
|
searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, true, OnlyReturnNum) |
|
|
|
return |
|
|
|
} else if TableName == "org" { |
|
|
|
searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, false, OnlyReturnNum) |
|
|
|
return |
|
|
|
} else if TableName == "dataset" { |
|
|
|
searchDataSet(ctx, "dataset-es-index", Key, Page, PageSize, OnlyReturnNum) |
|
|
|
return |
|
|
|
} else if TableName == "pr" { |
|
|
|
searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "t") |
|
|
|
//searchPR(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchRepoByLabel(ctx *context.Context, Key string, Page int, PageSize int) { |
|
|
|
/* |
|
|
|
项目, ES名称: repository-es-index |
|
|
|
搜索: |
|
|
|
name character varying(255) , 项目名称 |
|
|
|
description text, 项目描述 |
|
|
|
topics json, 标签 |
|
|
|
排序: |
|
|
|
updated_unix |
|
|
|
num_watches, |
|
|
|
num_stars, |
|
|
|
num_forks, |
|
|
|
*/ |
|
|
|
SortBy := ctx.Query("SortBy") |
|
|
|
PrivateTotal := ctx.QueryInt("PrivateTotal") |
|
|
|
WebTotal := ctx.QueryInt("WebTotal") |
|
|
|
ascending := ctx.QueryBool("Ascending") |
|
|
|
language := ctx.Query("language") |
|
|
|
if language == "" { |
|
|
|
language = "zh-CN" |
|
|
|
} |
|
|
|
from := (Page - 1) * PageSize |
|
|
|
resultObj := &SearchRes{} |
|
|
|
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) |
|
|
|
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) |
|
|
|
resultObj.Result = make([]map[string]interface{}, 0) |
|
|
|
if from == 0 { |
|
|
|
WebTotal = 0 |
|
|
|
} |
|
|
|
if ctx.User != nil && (from < PrivateTotal || from == 0) { |
|
|
|
orderBy := models.SearchOrderByRecentUpdated |
|
|
|
switch SortBy { |
|
|
|
case "updated_unix.keyword": |
|
|
|
orderBy = models.SearchOrderByRecentUpdated |
|
|
|
case "num_stars": |
|
|
|
orderBy = models.SearchOrderByStarsReverse |
|
|
|
case "num_forks": |
|
|
|
orderBy = models.SearchOrderByForksReverse |
|
|
|
case "num_watches": |
|
|
|
orderBy = models.SearchOrderByWatches |
|
|
|
} |
|
|
|
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) |
|
|
|
repos, count, err := models.SearchRepository(&models.SearchRepoOptions{ |
|
|
|
ListOptions: models.ListOptions{ |
|
|
|
Page: Page, |
|
|
|
PageSize: PageSize, |
|
|
|
}, |
|
|
|
Actor: ctx.User, |
|
|
|
OrderBy: orderBy, |
|
|
|
Private: true, |
|
|
|
OnlyPrivate: true, |
|
|
|
TopicOnly: true, |
|
|
|
TopicName: Key, |
|
|
|
IncludeDescription: setting.UI.SearchRepoDescription, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
ctx.JSON(200, "") |
|
|
|
return |
|
|
|
} |
|
|
|
resultObj.PrivateTotal = count |
|
|
|
if repos.Len() > 0 { |
|
|
|
log.Info("Query private repo number is:" + fmt.Sprint(repos.Len())) |
|
|
|
makePrivateRepo(repos, resultObj, Key, language) |
|
|
|
} else { |
|
|
|
log.Info("not found private repo,keyword=" + Key) |
|
|
|
} |
|
|
|
if repos.Len() >= PageSize { |
|
|
|
if WebTotal > 0 { |
|
|
|
resultObj.Total = int64(WebTotal) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
if ctx.User == nil { |
|
|
|
resultObj.PrivateTotal = 0 |
|
|
|
} else { |
|
|
|
resultObj.PrivateTotal = int64(PrivateTotal) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
from = from - PrivateTotal |
|
|
|
if from < 0 { |
|
|
|
from = 0 |
|
|
|
} |
|
|
|
Size := PageSize - len(resultObj.Result) |
|
|
|
|
|
|
|
log.Info("query searchRepoByLabel start") |
|
|
|
if Key != "" { |
|
|
|
boolQ := elastic.NewBoolQuery() |
|
|
|
topicsQuery := elastic.NewMatchQuery("topics", Key) |
|
|
|
boolQ.Should(topicsQuery) |
|
|
|
|
|
|
|
res, err := client.Search("repository-es-index").Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("topics")).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeRepoResult(res, "", false, language) |
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} else { |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func getSort(SortBy string, ascending bool) elastic.Sorter { |
|
|
|
var sort elastic.Sorter |
|
|
|
sort = elastic.NewScoreSort() |
|
|
|
if SortBy != "" { |
|
|
|
if SortBy == "default" { |
|
|
|
return sort |
|
|
|
} |
|
|
|
return elastic.NewFieldSort(SortBy).Order(ascending) |
|
|
|
} |
|
|
|
return sort |
|
|
|
} |
|
|
|
|
|
|
|
func searchRepo(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool) { |
|
|
|
/* |
|
|
|
项目, ES名称: repository-es-index |
|
|
|
搜索: |
|
|
|
name character varying(255) , 项目名称 |
|
|
|
description text, 项目描述 |
|
|
|
topics json, 标签 |
|
|
|
排序: |
|
|
|
updated_unix |
|
|
|
num_watches, |
|
|
|
num_stars, |
|
|
|
num_forks, |
|
|
|
*/ |
|
|
|
|
|
|
|
SortBy := ctx.Query("SortBy") |
|
|
|
PrivateTotal := ctx.QueryInt("PrivateTotal") |
|
|
|
WebTotal := ctx.QueryInt("WebTotal") |
|
|
|
ascending := ctx.QueryBool("Ascending") |
|
|
|
from := (Page - 1) * PageSize |
|
|
|
resultObj := &SearchRes{} |
|
|
|
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) |
|
|
|
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) |
|
|
|
resultObj.Result = make([]map[string]interface{}, 0) |
|
|
|
if from == 0 { |
|
|
|
WebTotal = 0 |
|
|
|
} |
|
|
|
language := ctx.Query("language") |
|
|
|
if language == "" { |
|
|
|
language = "zh-CN" |
|
|
|
} |
|
|
|
if ctx.User != nil && (from < PrivateTotal || from == 0) { |
|
|
|
orderBy := models.SearchOrderByRecentUpdated |
|
|
|
switch SortBy { |
|
|
|
case "updated_unix.keyword": |
|
|
|
orderBy = models.SearchOrderByRecentUpdated |
|
|
|
case "num_stars": |
|
|
|
orderBy = models.SearchOrderByStarsReverse |
|
|
|
case "num_forks": |
|
|
|
orderBy = models.SearchOrderByForksReverse |
|
|
|
case "num_watches": |
|
|
|
orderBy = models.SearchOrderByWatches |
|
|
|
} |
|
|
|
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) |
|
|
|
repos, count, err := models.SearchRepository(&models.SearchRepoOptions{ |
|
|
|
ListOptions: models.ListOptions{ |
|
|
|
Page: Page, |
|
|
|
PageSize: PageSize, |
|
|
|
}, |
|
|
|
Actor: ctx.User, |
|
|
|
OrderBy: orderBy, |
|
|
|
Private: true, |
|
|
|
OnlyPrivate: true, |
|
|
|
Keyword: Key, |
|
|
|
IncludeDescription: setting.UI.SearchRepoDescription, |
|
|
|
OnlySearchPrivate: true, |
|
|
|
}) |
|
|
|
if err != nil { |
|
|
|
ctx.JSON(200, "") |
|
|
|
return |
|
|
|
} |
|
|
|
resultObj.PrivateTotal = count |
|
|
|
if repos.Len() > 0 { |
|
|
|
log.Info("Query private repo number is:" + fmt.Sprint(repos.Len())) |
|
|
|
makePrivateRepo(repos, resultObj, Key, language) |
|
|
|
} else { |
|
|
|
log.Info("not found private repo,keyword=" + Key) |
|
|
|
} |
|
|
|
if repos.Len() >= PageSize { |
|
|
|
if WebTotal > 0 { |
|
|
|
resultObj.Total = int64(WebTotal) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
if ctx.User == nil { |
|
|
|
resultObj.PrivateTotal = 0 |
|
|
|
} else { |
|
|
|
resultObj.PrivateTotal = int64(PrivateTotal) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
from = from - PrivateTotal |
|
|
|
if from < 0 { |
|
|
|
from = 0 |
|
|
|
} |
|
|
|
Size := PageSize - len(resultObj.Result) |
|
|
|
|
|
|
|
log.Info("query searchRepo start") |
|
|
|
if Key != "" { |
|
|
|
boolQ := elastic.NewBoolQuery() |
|
|
|
nameQuery := elastic.NewMatchQuery("alias", Key).Boost(1024).QueryName("f_first") |
|
|
|
descriptionQuery := elastic.NewMatchQuery("description", Key).Boost(1.5).QueryName("f_second") |
|
|
|
topicsQuery := elastic.NewMatchQuery("topics", Key).Boost(1).QueryName("f_third") |
|
|
|
boolQ.Should(nameQuery, descriptionQuery, topicsQuery) |
|
|
|
|
|
|
|
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("alias", "description", "topics")).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeRepoResult(res, Key, OnlyReturnNum, language) |
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
isNeedSort := false |
|
|
|
if len(resultObj.Result) > 0 { |
|
|
|
isNeedSort = true |
|
|
|
} |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
if isNeedSort { |
|
|
|
sortRepo(resultObj.Result, SortBy, ascending) |
|
|
|
} |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("query all content.") |
|
|
|
//搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} |
|
|
|
res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeRepoResult(res, "", OnlyReturnNum, language) |
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func sortRepo(Result []map[string]interface{}, SortBy string, ascending bool) { |
|
|
|
orderBy := "" |
|
|
|
switch SortBy { |
|
|
|
case "updated_unix.keyword": |
|
|
|
orderBy = "updated_unix" |
|
|
|
case "num_stars": |
|
|
|
orderBy = "num_stars" |
|
|
|
case "num_forks": |
|
|
|
orderBy = "num_forks" |
|
|
|
case "num_watches": |
|
|
|
orderBy = "num_watches" |
|
|
|
} |
|
|
|
sort.Slice(Result, func(i, j int) bool { |
|
|
|
return getInt(Result[i][orderBy], orderBy) > getInt(Result[j][orderBy], orderBy) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
func getInt(tmp interface{}, orderBy string) int64 { |
|
|
|
timeInt, err := strconv.ParseInt(fmt.Sprint(tmp), 10, 64) |
|
|
|
if err == nil { |
|
|
|
return timeInt |
|
|
|
} else { |
|
|
|
log.Info("convert " + orderBy + " error type=" + fmt.Sprint(tmp)) |
|
|
|
} |
|
|
|
return -1 |
|
|
|
} |
|
|
|
|
|
|
|
func makePrivateRepo(repos models.RepositoryList, res *SearchRes, keyword string, language string) { |
|
|
|
|
|
|
|
for _, repo := range repos { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = repo.ID |
|
|
|
record["name"] = makeHighLight(keyword, repo.Name) |
|
|
|
record["real_name"] = repo.Name |
|
|
|
record["owner_name"] = repo.OwnerName |
|
|
|
record["description"] = truncLongText(makeHighLight(keyword, repo.Description), true) |
|
|
|
|
|
|
|
hightTopics := make([]string, 0) |
|
|
|
if len(repo.Topics) > 0 { |
|
|
|
for _, t := range repo.Topics { |
|
|
|
hightTopics = append(hightTopics, makeHighLight(keyword, t)) |
|
|
|
} |
|
|
|
} |
|
|
|
record["hightTopics"] = hightTopics |
|
|
|
|
|
|
|
record["num_watches"] = repo.NumWatches |
|
|
|
record["num_stars"] = repo.NumStars |
|
|
|
record["num_forks"] = repo.NumForks |
|
|
|
record["alias"] = truncLongText(makeHighLight(keyword, repo.Alias), true) |
|
|
|
record["lower_alias"] = repo.LowerAlias |
|
|
|
record["topics"] = repo.Topics |
|
|
|
record["avatar"] = repo.RelAvatarLink() |
|
|
|
if len(repo.RelAvatarLink()) == 0 { |
|
|
|
record["avatar"] = setting.RepositoryAvatarFallbackImage |
|
|
|
} |
|
|
|
record["updated_unix"] = repo.UpdatedUnix |
|
|
|
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) |
|
|
|
lang, err := repo.GetTopLanguageStats(1) |
|
|
|
if err == nil && len(lang) > 0 { |
|
|
|
record["lang"] = lang[0].Language |
|
|
|
} else { |
|
|
|
record["lang"] = "" |
|
|
|
} |
|
|
|
record["is_private"] = true |
|
|
|
res.Result = append(res.Result, record) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makeHighLight(keyword string, dest string) string { |
|
|
|
|
|
|
|
dest = replaceIngoreUpperOrLower(dest, strings.ToLower(dest), strings.ToLower(keyword)) |
|
|
|
|
|
|
|
return dest |
|
|
|
} |
|
|
|
|
|
|
|
func replaceIngoreUpperOrLower(dest string, destLower string, keywordLower string) string { |
|
|
|
re := "" |
|
|
|
last := 0 |
|
|
|
lenDestLower := len(destLower) |
|
|
|
lenkeywordLower := len(keywordLower) |
|
|
|
for i := 0; i < lenDestLower; i++ { |
|
|
|
if destLower[i] == keywordLower[0] { |
|
|
|
isFind := true |
|
|
|
for j := 1; j < lenkeywordLower; j++ { |
|
|
|
if (i+j) < lenDestLower && keywordLower[j] != destLower[i+j] { |
|
|
|
isFind = false |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if isFind && (i+lenkeywordLower) <= lenDestLower { |
|
|
|
re += dest[last:i] + "\u003cfont color='red'\u003e" + dest[i:(i+lenkeywordLower)] + "\u003c/font\u003e" |
|
|
|
i = i + lenkeywordLower |
|
|
|
last = i |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if last < lenDestLower { |
|
|
|
re += dest[last:lenDestLower] |
|
|
|
} |
|
|
|
return re |
|
|
|
} |
|
|
|
|
|
|
|
func makeRepoResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { |
|
|
|
total := sRes.Hits.TotalHits.Value |
|
|
|
result := make([]map[string]interface{}, 0) |
|
|
|
if !OnlyReturnNum { |
|
|
|
for i, hit := range sRes.Hits.Hits { |
|
|
|
log.Info("this is repo query " + fmt.Sprint(i) + " result.") |
|
|
|
recordSource := make(map[string]interface{}) |
|
|
|
source, err := hit.Source.MarshalJSON() |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
err = json.Unmarshal(source, &recordSource) |
|
|
|
if err == nil { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = hit.Id |
|
|
|
record["alias"] = getLabelValue("alias", recordSource, hit.Highlight) |
|
|
|
record["real_name"] = recordSource["name"] |
|
|
|
record["owner_name"] = recordSource["owner_name"] |
|
|
|
if recordSource["description"] != nil { |
|
|
|
desc := getLabelValue("description", recordSource, hit.Highlight) |
|
|
|
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) |
|
|
|
} else { |
|
|
|
record["description"] = "" |
|
|
|
} |
|
|
|
|
|
|
|
record["hightTopics"] = jsonStrToArray(getLabelValue("topics", recordSource, hit.Highlight)) |
|
|
|
record["num_watches"] = recordSource["num_watches"] |
|
|
|
record["num_stars"] = recordSource["num_stars"] |
|
|
|
record["num_forks"] = recordSource["num_forks"] |
|
|
|
record["lower_alias"] = recordSource["lower_alias"] |
|
|
|
if recordSource["topics"] != nil { |
|
|
|
topicsStr := recordSource["topics"].(string) |
|
|
|
log.Info("topicsStr=" + topicsStr) |
|
|
|
if topicsStr != "null" { |
|
|
|
record["topics"] = jsonStrToArray(topicsStr) |
|
|
|
} |
|
|
|
} |
|
|
|
if recordSource["avatar"] != nil { |
|
|
|
avatarstr := recordSource["avatar"].(string) |
|
|
|
if len(avatarstr) == 0 { |
|
|
|
record["avatar"] = setting.RepositoryAvatarFallbackImage |
|
|
|
} else { |
|
|
|
record["avatar"] = setting.AppSubURL + "/repo-avatars/" + avatarstr |
|
|
|
} |
|
|
|
} |
|
|
|
record["updated_unix"] = recordSource["updated_unix"] |
|
|
|
setUpdateHtml(record, recordSource["updated_unix"].(string), language) |
|
|
|
|
|
|
|
record["lang"] = recordSource["lang"] |
|
|
|
record["is_private"] = false |
|
|
|
result = append(result, record) |
|
|
|
} else { |
|
|
|
log.Info("deal repo source error," + err.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("deal repo source error," + err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
returnObj := &SearchRes{ |
|
|
|
Total: total, |
|
|
|
Result: result, |
|
|
|
} |
|
|
|
|
|
|
|
return returnObj |
|
|
|
} |
|
|
|
|
|
|
|
func setUpdateHtml(record map[string]interface{}, updated_unix string, language string) { |
|
|
|
timeInt, err := strconv.ParseInt(updated_unix, 10, 64) |
|
|
|
if err == nil { |
|
|
|
record["updated_html"] = timeutil.TimeSinceUnix(timeutil.TimeStamp(timeInt), language) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func jsonStrToArray(str string) []string { |
|
|
|
b := []byte(str) |
|
|
|
strs := make([]string, 0) |
|
|
|
err := json.Unmarshal(b, &strs) |
|
|
|
if err != nil { |
|
|
|
log.Info("convert str arrar error, str=" + str) |
|
|
|
} |
|
|
|
return strs |
|
|
|
} |
|
|
|
|
|
|
|
func dealLongText(text string, Key string, MatchedQueries []string) string { |
|
|
|
var isNeedToDealText bool |
|
|
|
isNeedToDealText = false |
|
|
|
if len(MatchedQueries) > 0 && Key != "" { |
|
|
|
if MatchedQueries[0] == "f_second" || MatchedQueries[0] == "f_third" { |
|
|
|
isNeedToDealText = true |
|
|
|
} |
|
|
|
} |
|
|
|
return truncLongText(text, isNeedToDealText) |
|
|
|
} |
|
|
|
|
|
|
|
func truncLongText(text string, isNeedToDealText bool) string { |
|
|
|
startStr := "color=" |
|
|
|
textRune := []rune(text) |
|
|
|
stringlen := len(textRune) |
|
|
|
if isNeedToDealText && stringlen > 200 { |
|
|
|
index := findFont(textRune, []rune(startStr)) |
|
|
|
if index > 0 { |
|
|
|
start := index - 50 |
|
|
|
if start < 0 { |
|
|
|
start = 0 |
|
|
|
} |
|
|
|
end := index + 150 |
|
|
|
if end >= stringlen { |
|
|
|
end = stringlen |
|
|
|
} |
|
|
|
return trimFontHtml(textRune[start:end]) + "..." |
|
|
|
} else { |
|
|
|
return trimFontHtml(textRune[0:200]) + "..." |
|
|
|
} |
|
|
|
} else { |
|
|
|
if stringlen > 200 { |
|
|
|
return trimFontHtml(textRune[0:200]) + "..." |
|
|
|
} else { |
|
|
|
return text |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func trimFontHtml(text []rune) string { |
|
|
|
startRune := rune('<') |
|
|
|
endRune := rune('>') |
|
|
|
count := 0 |
|
|
|
for i := 0; i < len(text); i++ { |
|
|
|
if text[i] == startRune { //start < |
|
|
|
re := false |
|
|
|
j := i + 1 |
|
|
|
for ; j < len(text); j++ { |
|
|
|
if text[j] == endRune { |
|
|
|
re = true |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if re { //found > |
|
|
|
i = j |
|
|
|
count++ |
|
|
|
} else { |
|
|
|
if count%2 == 1 { |
|
|
|
return string(text[0:i]) + "</font>" |
|
|
|
} else { |
|
|
|
return string(text[0:i]) |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return string(text) |
|
|
|
} |
|
|
|
|
|
|
|
func trimHrefHtml(result string) string { |
|
|
|
result = strings.Replace(result, "</a>", "", -1) |
|
|
|
result = strings.Replace(result, "\n", "", -1) |
|
|
|
var index int |
|
|
|
for { |
|
|
|
index = findSubstr(result, 0, "<a") |
|
|
|
if index != -1 { |
|
|
|
sIndex := findSubstr(result, index+2, ">") |
|
|
|
if sIndex != -1 { |
|
|
|
result = result[0:index] + result[sIndex+1:] |
|
|
|
} else { |
|
|
|
result = result[0:index] + result[index+2:] |
|
|
|
} |
|
|
|
} else { |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
return result |
|
|
|
} |
|
|
|
|
|
|
|
func findFont(text []rune, childText []rune) int { |
|
|
|
for i := 0; i < len(text); i++ { |
|
|
|
if text[i] == childText[0] { |
|
|
|
re := true |
|
|
|
for j, k := range childText { |
|
|
|
if k != text[i+j] { |
|
|
|
re = false |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if re { |
|
|
|
return i |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return -1 |
|
|
|
} |
|
|
|
|
|
|
|
func findSubstr(text string, startindex int, childText string) int { |
|
|
|
for i := startindex; i < len(text); i++ { |
|
|
|
if text[i] == childText[0] { |
|
|
|
re := true |
|
|
|
for k := range childText { |
|
|
|
if childText[k] != text[i+k] { |
|
|
|
re = false |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if re { |
|
|
|
return i |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return -1 |
|
|
|
} |
|
|
|
|
|
|
|
func searchUserOrOrg(ctx *context.Context, TableName string, Key string, Page int, PageSize int, IsQueryUser bool, OnlyReturnNum bool) { |
|
|
|
/* |
|
|
|
用户或者组织 ES名称: user-es-index |
|
|
|
搜索: |
|
|
|
name , 名称 |
|
|
|
full_name 全名 |
|
|
|
description 描述或者简介 |
|
|
|
排序: |
|
|
|
created_unix |
|
|
|
名称字母序 |
|
|
|
*/ |
|
|
|
SortBy := ctx.Query("SortBy") |
|
|
|
ascending := ctx.QueryBool("Ascending") |
|
|
|
boolQ := elastic.NewBoolQuery() |
|
|
|
|
|
|
|
typeValue := 1 |
|
|
|
if IsQueryUser { |
|
|
|
typeValue = 0 |
|
|
|
} |
|
|
|
UserOrOrgQuery := elastic.NewTermQuery("type", typeValue) |
|
|
|
if Key != "" { |
|
|
|
boolKeyQ := elastic.NewBoolQuery() |
|
|
|
log.Info("user or org Key=" + Key) |
|
|
|
nameQuery := elastic.NewMatchQuery("name", Key).Boost(2).QueryName("f_first") |
|
|
|
full_nameQuery := elastic.NewMatchQuery("full_name", Key).Boost(1.5).QueryName("f_second") |
|
|
|
descriptionQuery := elastic.NewMatchQuery("description", Key).Boost(1).QueryName("f_third") |
|
|
|
boolKeyQ.Should(nameQuery, full_nameQuery, descriptionQuery) |
|
|
|
boolQ.Must(UserOrOrgQuery, boolKeyQ) |
|
|
|
} else { |
|
|
|
boolQ.Must(UserOrOrgQuery) |
|
|
|
} |
|
|
|
|
|
|
|
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From((Page - 1) * PageSize).Size(PageSize).Highlight(queryHighlight("name", "full_name", "description")).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
result := makeUserOrOrgResult(res, Key, ctx, OnlyReturnNum) |
|
|
|
ctx.JSON(200, result) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func getLabelValue(key string, recordSource map[string]interface{}, searchHighliht elastic.SearchHitHighlight) string { |
|
|
|
if value, ok := searchHighliht[key]; !ok { |
|
|
|
if recordSource[key] != nil { |
|
|
|
return recordSource[key].(string) |
|
|
|
} else { |
|
|
|
return "" |
|
|
|
} |
|
|
|
} else { |
|
|
|
return value[0] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makeUserOrOrgResult(sRes *elastic.SearchResult, Key string, ctx *context.Context, OnlyReturnNum bool) *SearchRes { |
|
|
|
total := sRes.Hits.TotalHits.Value |
|
|
|
result := make([]map[string]interface{}, 0) |
|
|
|
if !OnlyReturnNum { |
|
|
|
for i, hit := range sRes.Hits.Hits { |
|
|
|
log.Info("this is user query " + fmt.Sprint(i) + " result.") |
|
|
|
recordSource := make(map[string]interface{}) |
|
|
|
source, err := hit.Source.MarshalJSON() |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
err = json.Unmarshal(source, &recordSource) |
|
|
|
if err == nil { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = hit.Id |
|
|
|
record["name"] = getLabelValue("name", recordSource, hit.Highlight) |
|
|
|
record["real_name"] = recordSource["name"] |
|
|
|
record["full_name"] = getLabelValue("full_name", recordSource, hit.Highlight) |
|
|
|
if recordSource["description"] != nil { |
|
|
|
desc := getLabelValue("description", recordSource, hit.Highlight) |
|
|
|
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) |
|
|
|
} else { |
|
|
|
record["description"] = "" |
|
|
|
} |
|
|
|
if ctx.User != nil { |
|
|
|
record["email"] = recordSource["email"] |
|
|
|
} else { |
|
|
|
record["email"] = "" |
|
|
|
} |
|
|
|
|
|
|
|
record["location"] = recordSource["location"] |
|
|
|
record["website"] = recordSource["website"] |
|
|
|
record["num_repos"] = recordSource["num_repos"] |
|
|
|
record["num_teams"] = recordSource["num_teams"] |
|
|
|
record["num_members"] = recordSource["num_members"] |
|
|
|
|
|
|
|
record["avatar"] = strings.TrimRight(setting.AppSubURL, "/") + "/user/avatar/" + recordSource["name"].(string) + "/" + strconv.Itoa(-1) |
|
|
|
record["updated_unix"] = recordSource["updated_unix"] |
|
|
|
record["created_unix"] = recordSource["created_unix"] |
|
|
|
record["add_time"] = getAddTime(recordSource["created_unix"].(string)) |
|
|
|
result = append(result, record) |
|
|
|
} else { |
|
|
|
log.Info("deal user source error," + err.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("deal user source error," + err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
returnObj := &SearchRes{ |
|
|
|
Total: total, |
|
|
|
Result: result, |
|
|
|
} |
|
|
|
return returnObj |
|
|
|
} |
|
|
|
|
|
|
|
func getAddTime(time string) string { |
|
|
|
timeInt, err := strconv.ParseInt(time, 10, 64) |
|
|
|
if err == nil { |
|
|
|
t := timeutil.TimeStamp(timeInt) |
|
|
|
return t.FormatShort() |
|
|
|
} |
|
|
|
return "" |
|
|
|
} |
|
|
|
|
|
|
|
func searchDataSet(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool) { |
|
|
|
/* |
|
|
|
数据集,ES名称:dataset-es-index |
|
|
|
搜索: |
|
|
|
title , 名称 |
|
|
|
description 描述 |
|
|
|
category 标签 |
|
|
|
file_name 数据集文件名称 |
|
|
|
排序: |
|
|
|
download_times |
|
|
|
|
|
|
|
*/ |
|
|
|
log.Info("query searchdataset start") |
|
|
|
SortBy := ctx.Query("SortBy") |
|
|
|
ascending := ctx.QueryBool("Ascending") |
|
|
|
PrivateTotal := ctx.QueryInt("PrivateTotal") |
|
|
|
WebTotal := ctx.QueryInt("WebTotal") |
|
|
|
language := ctx.Query("language") |
|
|
|
if language == "" { |
|
|
|
language = "zh-CN" |
|
|
|
} |
|
|
|
from := (Page - 1) * PageSize |
|
|
|
if from == 0 { |
|
|
|
WebTotal = 0 |
|
|
|
} |
|
|
|
resultObj := &SearchRes{} |
|
|
|
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) |
|
|
|
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) |
|
|
|
resultObj.Result = make([]map[string]interface{}, 0) |
|
|
|
|
|
|
|
if ctx.User != nil && (from < PrivateTotal || from == 0) { |
|
|
|
|
|
|
|
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) |
|
|
|
datasets, count, err := models.SearchDatasetBySQL(Page, PageSize, Key, ctx.User.ID) |
|
|
|
if err != nil { |
|
|
|
ctx.JSON(200, "") |
|
|
|
return |
|
|
|
} |
|
|
|
resultObj.PrivateTotal = count |
|
|
|
datasetSize := len(datasets) |
|
|
|
if datasetSize > 0 { |
|
|
|
log.Info("Query private dataset number is:" + fmt.Sprint(datasetSize) + " count=" + fmt.Sprint(count)) |
|
|
|
makePrivateDataSet(datasets, resultObj, Key, language) |
|
|
|
} else { |
|
|
|
log.Info("not found private dataset, keyword=" + Key) |
|
|
|
} |
|
|
|
if datasetSize >= PageSize { |
|
|
|
if WebTotal > 0 { //next page, not first query. |
|
|
|
resultObj.Total = int64(WebTotal) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
resultObj.PrivateTotal = int64(PrivateTotal) |
|
|
|
} |
|
|
|
|
|
|
|
from = from - PrivateTotal |
|
|
|
if from < 0 { |
|
|
|
from = 0 |
|
|
|
} |
|
|
|
Size := PageSize - len(resultObj.Result) |
|
|
|
|
|
|
|
boolQ := elastic.NewBoolQuery() |
|
|
|
if Key != "" { |
|
|
|
nameQuery := elastic.NewMatchQuery("title", Key).Boost(2).QueryName("f_first") |
|
|
|
descQuery := elastic.NewMatchQuery("description", Key).Boost(1.5).QueryName("f_second") |
|
|
|
fileNameQuery := elastic.NewMatchQuery("file_name", Key).Boost(1).QueryName("f_third") |
|
|
|
categoryQuery := elastic.NewMatchQuery("category", Key).Boost(1).QueryName("f_fourth") |
|
|
|
boolQ.Should(nameQuery, descQuery, categoryQuery, fileNameQuery) |
|
|
|
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("title", "description", "file_name", "category")).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeDatasetResult(res, Key, OnlyReturnNum, language) |
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
log.Info("query dataset es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("query all datasets.") |
|
|
|
//搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} |
|
|
|
res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeDatasetResult(res, "", OnlyReturnNum, language) |
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
log.Info("query dataset es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
ctx.JSON(200, "") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func makePrivateDataSet(datasets []*models.Dataset, res *SearchRes, Key string, language string) { |
|
|
|
for _, dataset := range datasets { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
|
|
|
|
record["id"] = dataset.ID |
|
|
|
userId := dataset.UserID |
|
|
|
|
|
|
|
user, errUser := models.GetUserByID(userId) |
|
|
|
if errUser == nil { |
|
|
|
record["owerName"] = user.GetDisplayName() |
|
|
|
record["avatar"] = user.RelAvatarLink() |
|
|
|
} |
|
|
|
|
|
|
|
repo, errRepo := models.GetRepositoryByID(dataset.RepoID) |
|
|
|
if errRepo == nil { |
|
|
|
log.Info("repo_url=" + repo.FullName()) |
|
|
|
record["repoUrl"] = repo.FullName() |
|
|
|
record["avatar"] = repo.RelAvatarLink() |
|
|
|
} else { |
|
|
|
log.Info("repo err=" + errRepo.Error()) |
|
|
|
} |
|
|
|
|
|
|
|
record["title"] = makeHighLight(Key, dataset.Title) |
|
|
|
record["description"] = truncLongText(makeHighLight(Key, dataset.Description), true) |
|
|
|
|
|
|
|
record["category"] = dataset.Category |
|
|
|
record["task"] = dataset.Task |
|
|
|
record["download_times"] = dataset.DownloadTimes |
|
|
|
record["created_unix"] = dataset.CreatedUnix |
|
|
|
record["updated_unix"] = repo.UpdatedUnix |
|
|
|
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) |
|
|
|
|
|
|
|
res.Result = append(res.Result, record) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makeDatasetResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { |
|
|
|
total := sRes.Hits.TotalHits.Value |
|
|
|
result := make([]map[string]interface{}, 0) |
|
|
|
if !OnlyReturnNum { |
|
|
|
for i, hit := range sRes.Hits.Hits { |
|
|
|
log.Info("this is dataset query " + fmt.Sprint(i) + " result.") |
|
|
|
recordSource := make(map[string]interface{}) |
|
|
|
source, err := hit.Source.MarshalJSON() |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
err = json.Unmarshal(source, &recordSource) |
|
|
|
if err == nil { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = hit.Id |
|
|
|
userIdStr := recordSource["user_id"].(string) |
|
|
|
userId, cerr := strconv.ParseInt(userIdStr, 10, 64) |
|
|
|
if cerr == nil { |
|
|
|
user, errUser := models.GetUserByID(userId) |
|
|
|
if errUser == nil { |
|
|
|
record["owerName"] = user.GetDisplayName() |
|
|
|
record["avatar"] = user.RelAvatarLink() |
|
|
|
} |
|
|
|
} |
|
|
|
setRepoInfo(recordSource, record) |
|
|
|
record["title"] = getLabelValue("title", recordSource, hit.Highlight) |
|
|
|
record["category"] = getLabelValue("category", recordSource, hit.Highlight) |
|
|
|
if recordSource["description"] != nil { |
|
|
|
desc := getLabelValue("description", recordSource, hit.Highlight) |
|
|
|
record["description"] = dealLongText(desc, Key, hit.MatchedQueries) |
|
|
|
} else { |
|
|
|
record["description"] = "" |
|
|
|
} |
|
|
|
record["file_name"] = getDatasetFileName(getLabelValue("file_name", recordSource, hit.Highlight)) |
|
|
|
record["task"] = recordSource["task"] |
|
|
|
record["download_times"] = recordSource["download_times"] |
|
|
|
record["created_unix"] = recordSource["created_unix"] |
|
|
|
setUpdateHtml(record, recordSource["updated_unix"].(string), language) |
|
|
|
result = append(result, record) |
|
|
|
} else { |
|
|
|
log.Info("deal dataset source error," + err.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("deal dataset source error," + err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
returnObj := &SearchRes{ |
|
|
|
Total: total, |
|
|
|
Result: result, |
|
|
|
} |
|
|
|
|
|
|
|
return returnObj |
|
|
|
} |
|
|
|
|
|
|
|
func getDatasetFileName(fileName string) string { |
|
|
|
slices := strings.Split(fileName, "-#,#-") |
|
|
|
fileName = strings.Join(slices, ", ") |
|
|
|
return fileName |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueOrPr(ctx *context.Context, TableName string, Key string, Page int, PageSize int, OnlyReturnNum bool, issueOrPr string) { |
|
|
|
|
|
|
|
/* |
|
|
|
任务,合并请求 ES名称:issue-es-index |
|
|
|
搜索: |
|
|
|
name character varying(255) , 标题 |
|
|
|
content text, 内容 |
|
|
|
comment text, 评论 |
|
|
|
排序: |
|
|
|
updated_unix |
|
|
|
*/ |
|
|
|
SortBy := ctx.Query("SortBy") |
|
|
|
ascending := ctx.QueryBool("Ascending") |
|
|
|
PrivateTotal := ctx.QueryInt("PrivateTotal") |
|
|
|
WebTotal := ctx.QueryInt("WebTotal") |
|
|
|
language := ctx.Query("language") |
|
|
|
if language == "" { |
|
|
|
language = "zh-CN" |
|
|
|
} |
|
|
|
from := (Page - 1) * PageSize |
|
|
|
if from == 0 { |
|
|
|
WebTotal = 0 |
|
|
|
} |
|
|
|
resultObj := &SearchRes{} |
|
|
|
log.Info("WebTotal=" + fmt.Sprint(WebTotal)) |
|
|
|
log.Info("PrivateTotal=" + fmt.Sprint(PrivateTotal)) |
|
|
|
resultObj.Result = make([]map[string]interface{}, 0) |
|
|
|
isPull := false |
|
|
|
if issueOrPr == "t" { |
|
|
|
isPull = true |
|
|
|
} |
|
|
|
|
|
|
|
if ctx.User != nil && (from < PrivateTotal || from == 0) { |
|
|
|
|
|
|
|
log.Info("actor is null?:" + fmt.Sprint(ctx.User == nil)) |
|
|
|
issues, count, err := models.SearchPrivateIssueOrPr(Page, PageSize, Key, isPull, ctx.User.ID) |
|
|
|
if err != nil { |
|
|
|
ctx.JSON(200, "") |
|
|
|
return |
|
|
|
} |
|
|
|
resultObj.PrivateTotal = count |
|
|
|
issuesSize := len(issues) |
|
|
|
if issuesSize > 0 { |
|
|
|
log.Info("Query private repo issue number is:" + fmt.Sprint(issuesSize) + " count=" + fmt.Sprint(count)) |
|
|
|
makePrivateIssueOrPr(issues, resultObj, Key, language) |
|
|
|
} else { |
|
|
|
log.Info("not found private repo issue,keyword=" + Key) |
|
|
|
} |
|
|
|
if issuesSize >= PageSize { |
|
|
|
if WebTotal > 0 { //next page, not first query. |
|
|
|
resultObj.Total = int64(WebTotal) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
resultObj.PrivateTotal = int64(PrivateTotal) |
|
|
|
} |
|
|
|
|
|
|
|
from = from - PrivateTotal |
|
|
|
if from < 0 { |
|
|
|
from = 0 |
|
|
|
} |
|
|
|
Size := PageSize - len(resultObj.Result) |
|
|
|
|
|
|
|
boolQ := elastic.NewBoolQuery() |
|
|
|
isIssueQuery := elastic.NewTermQuery("is_pull", issueOrPr) |
|
|
|
|
|
|
|
if Key != "" { |
|
|
|
boolKeyQ := elastic.NewBoolQuery() |
|
|
|
log.Info("issue Key=" + Key) |
|
|
|
nameQuery := elastic.NewMatchQuery("name", Key).Boost(2).QueryName("f_first") |
|
|
|
contentQuery := elastic.NewMatchQuery("content", Key).Boost(1.5).QueryName("f_second") |
|
|
|
commentQuery := elastic.NewMatchQuery("comment", Key).Boost(1).QueryName("f_third") |
|
|
|
boolKeyQ.Should(nameQuery, contentQuery, commentQuery) |
|
|
|
boolQ.Must(isIssueQuery, boolKeyQ) |
|
|
|
} else { |
|
|
|
boolQ.Must(isIssueQuery) |
|
|
|
} |
|
|
|
|
|
|
|
res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("name", "content", "comment")).Do(ctx.Req.Context()) |
|
|
|
if err == nil { |
|
|
|
searchJson, _ := json.Marshal(res) |
|
|
|
log.Info("searchJson=" + string(searchJson)) |
|
|
|
esresult := makeIssueResult(res, Key, OnlyReturnNum, language) |
|
|
|
|
|
|
|
resultObj.Total = resultObj.PrivateTotal + esresult.Total |
|
|
|
log.Info("query issue es count=" + fmt.Sprint(esresult.Total) + " total=" + fmt.Sprint(resultObj.Total)) |
|
|
|
resultObj.Result = append(resultObj.Result, esresult.Result...) |
|
|
|
ctx.JSON(200, resultObj) |
|
|
|
} else { |
|
|
|
log.Info("query es error," + err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func queryHighlight(names ...string) *elastic.Highlight { |
|
|
|
re := elastic.NewHighlight() |
|
|
|
for i := 0; i < len(names); i++ { |
|
|
|
field := &elastic.HighlighterField{ |
|
|
|
Name: names[i], |
|
|
|
} |
|
|
|
re.Fields(field) |
|
|
|
} |
|
|
|
re.PreTags("<font color='red'>") |
|
|
|
re.PostTags("</font>") |
|
|
|
return re |
|
|
|
} |
|
|
|
|
|
|
|
func setRepoInfo(recordSource map[string]interface{}, record map[string]interface{}) { |
|
|
|
repoIdstr := recordSource["repo_id"].(string) |
|
|
|
repoId, cerr := strconv.ParseInt(repoIdstr, 10, 64) |
|
|
|
if cerr == nil { |
|
|
|
repo, errRepo := models.GetRepositoryByID(repoId) |
|
|
|
if errRepo == nil { |
|
|
|
log.Info("repo_url=" + repo.FullName()) |
|
|
|
record["repoUrl"] = repo.FullName() |
|
|
|
record["avatar"] = repo.RelAvatarLink() |
|
|
|
} else { |
|
|
|
log.Info("repo err=" + errRepo.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("parse int err=" + cerr.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makePrivateIssueOrPr(issues []*models.Issue, res *SearchRes, Key string, language string) { |
|
|
|
for _, issue := range issues { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = issue.ID |
|
|
|
record["repo_id"] = issue.RepoID |
|
|
|
|
|
|
|
repo, errRepo := models.GetRepositoryByID(issue.RepoID) |
|
|
|
if errRepo == nil { |
|
|
|
log.Info("repo_url=" + repo.FullName()) |
|
|
|
record["repoUrl"] = repo.FullName() |
|
|
|
record["avatar"] = repo.RelAvatarLink() |
|
|
|
} else { |
|
|
|
log.Info("repo err=" + errRepo.Error()) |
|
|
|
} |
|
|
|
record["name"] = makeHighLight(Key, issue.Title) |
|
|
|
record["content"] = truncLongText(makeHighLight(Key, issue.Content), true) |
|
|
|
|
|
|
|
if issue.IsPull { |
|
|
|
pr, err1 := issue.GetPullRequest() |
|
|
|
if err1 == nil && pr != nil { |
|
|
|
record["pr_id"] = pr.ID |
|
|
|
} |
|
|
|
} |
|
|
|
record["index"] = issue.Index |
|
|
|
record["num_comments"] = issue.NumComments |
|
|
|
record["is_closed"] = issue.IsClosed |
|
|
|
record["updated_unix"] = issue.UpdatedUnix |
|
|
|
record["updated_html"] = timeutil.TimeSinceUnix(repo.UpdatedUnix, language) |
|
|
|
res.Result = append(res.Result, record) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func makeIssueResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool, language string) *SearchRes { |
|
|
|
total := sRes.Hits.TotalHits.Value |
|
|
|
result := make([]map[string]interface{}, 0) |
|
|
|
if !OnlyReturnNum { |
|
|
|
for i, hit := range sRes.Hits.Hits { |
|
|
|
log.Info("this is issue query " + fmt.Sprint(i) + " result.") |
|
|
|
recordSource := make(map[string]interface{}) |
|
|
|
source, err := hit.Source.MarshalJSON() |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
err = json.Unmarshal(source, &recordSource) |
|
|
|
if err == nil { |
|
|
|
record := make(map[string]interface{}) |
|
|
|
record["id"] = hit.Id |
|
|
|
record["repo_id"] = recordSource["repo_id"] |
|
|
|
log.Info("recordSource[\"repo_id\"]=" + fmt.Sprint(recordSource["repo_id"])) |
|
|
|
setRepoInfo(recordSource, record) |
|
|
|
record["name"] = getLabelValue("name", recordSource, hit.Highlight) |
|
|
|
if recordSource["content"] != nil { |
|
|
|
desc := getLabelValue("content", recordSource, hit.Highlight) |
|
|
|
record["content"] = dealLongText(desc, Key, hit.MatchedQueries) |
|
|
|
if _, ok := hit.Highlight["content"]; !ok { |
|
|
|
if _, ok_comment := hit.Highlight["comment"]; ok_comment { |
|
|
|
desc := getLabelValue("comment", recordSource, hit.Highlight) |
|
|
|
record["content"] = trimHrefHtml(dealLongText(desc, Key, hit.MatchedQueries)) |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
if recordSource["comment"] != nil { |
|
|
|
desc := getLabelValue("comment", recordSource, hit.Highlight) |
|
|
|
record["content"] = dealLongText(desc, Key, hit.MatchedQueries) |
|
|
|
} |
|
|
|
} |
|
|
|
if recordSource["pr_id"] != nil { |
|
|
|
record["pr_id"] = recordSource["pr_id"] |
|
|
|
} |
|
|
|
log.Info("index=" + recordSource["index"].(string)) |
|
|
|
record["index"] = recordSource["index"] |
|
|
|
record["num_comments"] = recordSource["num_comments"] |
|
|
|
record["is_closed"] = recordSource["is_closed"] |
|
|
|
record["updated_unix"] = recordSource["updated_unix"] |
|
|
|
setUpdateHtml(record, recordSource["updated_unix"].(string), language) |
|
|
|
result = append(result, record) |
|
|
|
} else { |
|
|
|
log.Info("deal issue source error," + err.Error()) |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.Info("deal issue source error," + err.Error()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
returnObj := &SearchRes{ |
|
|
|
Total: total, |
|
|
|
Result: result, |
|
|
|
} |
|
|
|
|
|
|
|
return returnObj |
|
|
|
} |