diff --git a/models/repo_list.go b/models/repo_list.go index 3c655fbd9..61410e08e 100755 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -192,6 +192,8 @@ type SearchRepoOptions struct { // False -> include just no courses Course util.OptionalBool OnlySearchPrivate bool + + RepoIds []int64 } //SearchOrderBy is used to sort the result @@ -206,6 +208,7 @@ type FindReposResponse struct { Page int PageSize int Total int64 + RepoIds []int64 } // Strings for sorting result @@ -281,6 +284,33 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { if opts.StarredByID > 0 { cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID}))) } + if len(opts.RepoIds) > 0 { + const MaxINItems = 1000 + if len(opts.RepoIds) <= MaxINItems { + cond = cond.And(builder.In("id", opts.RepoIds)) + } else { + repoIdsMap := make(map[int][]int64, 0) + i := 0 + + for j := 0; j < len(opts.RepoIds); j++ { + if _, ok := repoIdsMap[i]; !ok { + repoIdsMap[i] = make([]int64, 0) + } + repoIdsMap[i] = append(repoIdsMap[i], opts.RepoIds[j]) + if (j+1)%MaxINItems == 0 { + i += 1 + } + + } + subCond := builder.NewCond() + for _, repoSplit := range repoIdsMap { + subCond = subCond.Or(builder.In("id", repoSplit)) + } + cond = cond.And(subCond) + + } + + } // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate if opts.OwnerID > 0 { diff --git a/models/tech_converge_info.go b/models/tech_converge_info.go index 46aa163f2..a13c216c8 100644 --- a/models/tech_converge_info.go +++ b/models/tech_converge_info.go @@ -10,10 +10,11 @@ import ( ) const ( - TechHide = 1 - TechShow = 2 + TechShow = 1 + TechHide = 2 TechMigrating = 3 TechMigrateFailed = 4 + TechNotExist = 5 ) const DefaultTechApprovedStatus = TechShow @@ -161,6 +162,16 @@ func GetProjectNames() []string { x.Table("tech_converge_base_info").Distinct("project_name").Find(&names) return names } +func GetIdByProjectName(name string) []string { + var ids []int64 + x.Table("tech_converge_base_info").Cols("id").Where("project_name=?", name).Find(&ids) + + idStrs := make([]string, 0, len(ids)) + for _, id := range ids { + idStrs = append(idStrs, strconv.FormatInt(id, 10)) + } + return idStrs +} func GetSummitRepoIds() []int64 { var ids []int64 x.Table("repo_converge_info").Cols("repo_id").Find(&ids) @@ -326,10 +337,37 @@ type TechRepoInfo struct { Repos []*RepoWithInstitution } -func SearchTechRepoInfo(opt SearchTechOpt) ([]*TechRepoInfo, int64, error) { +func GetAvailableRepoConvergeInfo(opt *SearchRepoOpt) ([]*RepoConvergeInfo, error) { + + repos := make([]*RepoConvergeInfo, 0) + err := x.Table("repo_converge_info").Where(buildRepoFilterCond(opt)).Find(&repos) + return repos, err + +} + +func buildRepoFilterCond(opt *SearchRepoOpt) string { + + sql := "" + + if opt.Institution != "" { + sql += getPrefixWithoutWhere(sql) + " (institution like '%" + opt.Institution + ",%'" + " or institution like '%," + opt.Institution + "%'" + " or institution = '" + opt.Institution + "')" + } + + if opt.ProjectName != "" { + baseInfoIds := GetIdByProjectName(opt.ProjectName) + if len(baseInfoIds) > 0 { + + sql += getPrefixWithoutWhere(sql) + " id in (" + strings.Join(baseInfoIds, ",") + ")" + } + + } + return sql +} + +func SearchTechRepoInfo(opt *SearchTechOpt) ([]*TechRepoInfo, int64, error) { sql := `select a.*,COALESCE(b.count,0) as repo_count, COALESCE(b.max,0) as max from tech_converge_base_info a left join - (select base_info_id,count(id),max(updated_unix) from repo_converge_info where status=2 GROUP BY base_info_id ) b + (select base_info_id,count(id),max(updated_unix) from repo_converge_info where status=` + strconv.Itoa(TechShow) + ` GROUP BY base_info_id ) b on a.id=b.base_info_id` totalSql := "select count(*) from (" + sql + ") c" + buildTechFilterCond(opt) total, err := x.SQL(totalSql).Count(new(TechConvergeBaseInfo)) @@ -363,7 +401,7 @@ func SearchTechRepoInfo(opt SearchTechOpt) ([]*TechRepoInfo, int64, error) { } -func buildTechFilterCond(opt SearchTechOpt) string { +func buildTechFilterCond(opt *SearchTechOpt) string { sql := "" @@ -394,6 +432,13 @@ func getWherePrefix(sql string) string { return " and " } +func getPrefixWithoutWhere(sql string) string { + if sql == "" { + return "" + } + return " and " +} + func loadRepoInfoForTech(list []*TechRepoInfo) { for _, techRepo := range list { diff --git a/routers/api/v1/tech/tech.go b/routers/api/v1/tech/tech.go index 6576202cf..d19056ce0 100644 --- a/routers/api/v1/tech/tech.go +++ b/routers/api/v1/tech/tech.go @@ -47,11 +47,38 @@ func GetFilterInfo(ctx *context.APIContext) { func SearchRepoInfo(ctx *context.APIContext) { + opts := &models.SearchRepoOpt{} + opts.Q = ctx.Query("name") + opts.ProjectName = ctx.Query("tech_name") + opts.Topic = ctx.Query("topic") + opts.Institution = ctx.Query("institution_name") + page := ctx.QueryInt("page") + if page <= 0 { + page = 1 + } + opts.Page = page + pageSize := ctx.QueryInt("pageSize") + if pageSize <= 0 { + pageSize = 30 + } + opts.PageSize = pageSize + orderBy := ctx.Query("sort") + opts.OrderBy = orderBy + infos, total, err := techService.SearchRepoInfoWithInstitution(opts) + if err != nil { + log.Error("search has error", err) + ctx.JSON(http.StatusOK, map[string]interface { + }{"total": 0, "data": []*models.RepoWithInstitution{}}) + } else { + ctx.JSON(http.StatusOK, map[string]interface { + }{"total": total, "data": infos}) + } + } func SearchTechProjectInfo(ctx *context.APIContext) { - opts := models.SearchTechOpt{} + opts := &models.SearchTechOpt{} opts.Q = ctx.Query("name") opts.ApplyYear = ctx.QueryInt("apply_year") opts.ExecuteYear = ctx.QueryInt("execute_year") @@ -67,7 +94,7 @@ func SearchTechProjectInfo(ctx *context.APIContext) { pageSize = 15 } opts.PageSize = pageSize - orderBy := ctx.Query("orderBy") + orderBy := ctx.Query("sort") if orderBy == "" || orderBy == "count" { opts.OrderBy = "order by repo_count desc, max desc " } else { diff --git a/services/repository/square.go b/services/repository/square.go index d68e5b189..f25abb28e 100644 --- a/services/repository/square.go +++ b/services/repository/square.go @@ -169,6 +169,7 @@ type FindReposOptions struct { Topic string Private bool OwnerID int64 + RepoIds []int64 } func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { @@ -224,6 +225,7 @@ func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { AllLimited: true, TopicName: opts.Topic, IncludeDescription: setting.UI.SearchRepoDescription, + RepoIds: opts.RepoIds, }) if err != nil { log.Error("FindRepos error when SearchRepository.%v", err) diff --git a/services/tech/tech.go b/services/tech/tech.go index 9a4dadbc4..28b52c84c 100644 --- a/services/tech/tech.go +++ b/services/tech/tech.go @@ -1,6 +1,9 @@ package tech -import "code.gitea.io/gitea/models" +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/services/repository" +) func FindTech(opt models.FindTechOpt) ([]*models.TechConvergeBrief, error) { techList, err := models.FindTech(opt) @@ -14,6 +17,55 @@ func FindTech(opt models.FindTechOpt) ([]*models.TechConvergeBrief, error) { return r, nil } +func SearchRepoInfoWithInstitution(opt *models.SearchRepoOpt) ([]*models.RepoWithInstitution, int64, error) { + infos, err := models.GetAvailableRepoConvergeInfo(opt) + if err != nil { + return nil, 0, err + } + repoIds, institutionMap := getRepoIdAndInstitutionMap(infos) + + result, err := repository.FindRepos(repository.FindReposOptions{ + ListOptions: models.ListOptions{Page: opt.Page, PageSize: opt.PageSize}, + Sort: opt.OrderBy, + Keyword: opt.Q, + Topic: opt.Topic, + RepoIds: repoIds, + }) + + if err != nil { + return nil, 0, err + } + repoResult := make([]*models.RepoWithInstitution, 0, len(result.Repos)) + + for _, repo := range result.Repos { + repoResult = append(repoResult, &models.RepoWithInstitution{ + ID: repo.ID, + OwnerID: repo.OwnerID, + OwnerName: repo.OwnerName, + Name: repo.Name, + Topics: repo.Topics, + Description: repo.Description, + Institution: institutionMap[repo.ID], + UpdatedUnix: repo.UpdatedUnix, + }) + } + + return repoResult, result.Total, nil + +} + +func getRepoIdAndInstitutionMap(infos []*models.RepoConvergeInfo) ([]int64, map[int64]string) { + repoIds := make([]int64, 0, len(infos)) + institutionMap := make(map[int64]string, 0) + // We only need the keys + for _, info := range infos { + repoIds = append(repoIds, info.RepoID) + institutionMap[info.RepoID] = info.Institution + } + return repoIds, institutionMap +} + + func IsValidRepoConvergeExists(repoId, baseInfoId int64) (bool, error) { list, err := models.GetRepoConverge(models.GetRepoConvergeOpts{ Status: []int{models.TechHide, models.TechShow, models.TechMigrating},