@@ -192,6 +192,8 @@ type SearchRepoOptions struct { | |||||
// False -> include just no courses | // False -> include just no courses | ||||
Course util.OptionalBool | Course util.OptionalBool | ||||
OnlySearchPrivate bool | OnlySearchPrivate bool | ||||
RepoIds []int64 | |||||
} | } | ||||
//SearchOrderBy is used to sort the result | //SearchOrderBy is used to sort the result | ||||
@@ -206,6 +208,7 @@ type FindReposResponse struct { | |||||
Page int | Page int | ||||
PageSize int | PageSize int | ||||
Total int64 | Total int64 | ||||
RepoIds []int64 | |||||
} | } | ||||
// Strings for sorting result | // Strings for sorting result | ||||
@@ -281,6 +284,33 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||||
if opts.StarredByID > 0 { | if opts.StarredByID > 0 { | ||||
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID}))) | 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 | // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate | ||||
if opts.OwnerID > 0 { | if opts.OwnerID > 0 { | ||||
@@ -10,10 +10,11 @@ import ( | |||||
) | ) | ||||
const ( | const ( | ||||
TechHide = 1 | |||||
TechShow = 2 | |||||
TechShow = 1 | |||||
TechHide = 2 | |||||
TechMigrating = 3 | TechMigrating = 3 | ||||
TechMigrateFailed = 4 | TechMigrateFailed = 4 | ||||
TechNotExist = 5 | |||||
) | ) | ||||
const DefaultTechApprovedStatus = TechShow | const DefaultTechApprovedStatus = TechShow | ||||
@@ -161,6 +162,16 @@ func GetProjectNames() []string { | |||||
x.Table("tech_converge_base_info").Distinct("project_name").Find(&names) | x.Table("tech_converge_base_info").Distinct("project_name").Find(&names) | ||||
return 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 { | func GetSummitRepoIds() []int64 { | ||||
var ids []int64 | var ids []int64 | ||||
x.Table("repo_converge_info").Cols("repo_id").Find(&ids) | x.Table("repo_converge_info").Cols("repo_id").Find(&ids) | ||||
@@ -326,10 +337,37 @@ type TechRepoInfo struct { | |||||
Repos []*RepoWithInstitution | 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 | 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` | on a.id=b.base_info_id` | ||||
totalSql := "select count(*) from (" + sql + ") c" + buildTechFilterCond(opt) | totalSql := "select count(*) from (" + sql + ") c" + buildTechFilterCond(opt) | ||||
total, err := x.SQL(totalSql).Count(new(TechConvergeBaseInfo)) | 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 := "" | sql := "" | ||||
@@ -394,6 +432,13 @@ func getWherePrefix(sql string) string { | |||||
return " and " | return " and " | ||||
} | } | ||||
func getPrefixWithoutWhere(sql string) string { | |||||
if sql == "" { | |||||
return "" | |||||
} | |||||
return " and " | |||||
} | |||||
func loadRepoInfoForTech(list []*TechRepoInfo) { | func loadRepoInfoForTech(list []*TechRepoInfo) { | ||||
for _, techRepo := range list { | for _, techRepo := range list { | ||||
@@ -47,11 +47,38 @@ func GetFilterInfo(ctx *context.APIContext) { | |||||
func SearchRepoInfo(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) { | func SearchTechProjectInfo(ctx *context.APIContext) { | ||||
opts := models.SearchTechOpt{} | |||||
opts := &models.SearchTechOpt{} | |||||
opts.Q = ctx.Query("name") | opts.Q = ctx.Query("name") | ||||
opts.ApplyYear = ctx.QueryInt("apply_year") | opts.ApplyYear = ctx.QueryInt("apply_year") | ||||
opts.ExecuteYear = ctx.QueryInt("execute_year") | opts.ExecuteYear = ctx.QueryInt("execute_year") | ||||
@@ -67,7 +94,7 @@ func SearchTechProjectInfo(ctx *context.APIContext) { | |||||
pageSize = 15 | pageSize = 15 | ||||
} | } | ||||
opts.PageSize = pageSize | opts.PageSize = pageSize | ||||
orderBy := ctx.Query("orderBy") | |||||
orderBy := ctx.Query("sort") | |||||
if orderBy == "" || orderBy == "count" { | if orderBy == "" || orderBy == "count" { | ||||
opts.OrderBy = "order by repo_count desc, max desc " | opts.OrderBy = "order by repo_count desc, max desc " | ||||
} else { | } else { | ||||
@@ -169,6 +169,7 @@ type FindReposOptions struct { | |||||
Topic string | Topic string | ||||
Private bool | Private bool | ||||
OwnerID int64 | OwnerID int64 | ||||
RepoIds []int64 | |||||
} | } | ||||
func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { | func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { | ||||
@@ -224,6 +225,7 @@ func FindRepos(opts FindReposOptions) (*models.FindReposResponse, error) { | |||||
AllLimited: true, | AllLimited: true, | ||||
TopicName: opts.Topic, | TopicName: opts.Topic, | ||||
IncludeDescription: setting.UI.SearchRepoDescription, | IncludeDescription: setting.UI.SearchRepoDescription, | ||||
RepoIds: opts.RepoIds, | |||||
}) | }) | ||||
if err != nil { | if err != nil { | ||||
log.Error("FindRepos error when SearchRepository.%v", err) | log.Error("FindRepos error when SearchRepository.%v", err) | ||||
@@ -1,6 +1,9 @@ | |||||
package tech | 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) { | func FindTech(opt models.FindTechOpt) ([]*models.TechConvergeBrief, error) { | ||||
techList, err := models.FindTech(opt) | techList, err := models.FindTech(opt) | ||||
@@ -14,6 +17,55 @@ func FindTech(opt models.FindTechOpt) ([]*models.TechConvergeBrief, error) { | |||||
return r, nil | 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) { | func IsValidRepoConvergeExists(repoId, baseInfoId int64) (bool, error) { | ||||
list, err := models.GetRepoConverge(models.GetRepoConvergeOpts{ | list, err := models.GetRepoConverge(models.GetRepoConvergeOpts{ | ||||
Status: []int{models.TechHide, models.TechShow, models.TechMigrating}, | Status: []int{models.TechHide, models.TechShow, models.TechMigrating}, | ||||