Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/modules/util"
  9. "github.com/go-xorm/builder"
  10. )
  11. // RepositoryList contains a list of repositories
  12. type RepositoryList []*Repository
  13. func (repos RepositoryList) Len() int {
  14. return len(repos)
  15. }
  16. func (repos RepositoryList) Less(i, j int) bool {
  17. return repos[i].FullName() < repos[j].FullName()
  18. }
  19. func (repos RepositoryList) Swap(i, j int) {
  20. repos[i], repos[j] = repos[j], repos[i]
  21. }
  22. // RepositoryListOfMap make list from values of map
  23. func RepositoryListOfMap(repoMap map[int64]*Repository) RepositoryList {
  24. return RepositoryList(valuesRepository(repoMap))
  25. }
  26. func (repos RepositoryList) loadAttributes(e Engine) error {
  27. if len(repos) == 0 {
  28. return nil
  29. }
  30. // Load owners.
  31. set := make(map[int64]struct{})
  32. for i := range repos {
  33. set[repos[i].OwnerID] = struct{}{}
  34. }
  35. users := make(map[int64]*User, len(set))
  36. if err := e.
  37. Where("id > 0").
  38. In("id", keysInt64(set)).
  39. Find(&users); err != nil {
  40. return fmt.Errorf("find users: %v", err)
  41. }
  42. for i := range repos {
  43. repos[i].Owner = users[repos[i].OwnerID]
  44. }
  45. return nil
  46. }
  47. // LoadAttributes loads the attributes for the given RepositoryList
  48. func (repos RepositoryList) LoadAttributes() error {
  49. return repos.loadAttributes(x)
  50. }
  51. // MirrorRepositoryList contains the mirror repositories
  52. type MirrorRepositoryList []*Repository
  53. func (repos MirrorRepositoryList) loadAttributes(e Engine) error {
  54. if len(repos) == 0 {
  55. return nil
  56. }
  57. // Load mirrors.
  58. repoIDs := make([]int64, 0, len(repos))
  59. for i := range repos {
  60. if !repos[i].IsMirror {
  61. continue
  62. }
  63. repoIDs = append(repoIDs, repos[i].ID)
  64. }
  65. mirrors := make([]*Mirror, 0, len(repoIDs))
  66. if err := e.
  67. Where("id > 0").
  68. In("repo_id", repoIDs).
  69. Find(&mirrors); err != nil {
  70. return fmt.Errorf("find mirrors: %v", err)
  71. }
  72. set := make(map[int64]*Mirror)
  73. for i := range mirrors {
  74. set[mirrors[i].RepoID] = mirrors[i]
  75. }
  76. for i := range repos {
  77. repos[i].Mirror = set[repos[i].ID]
  78. }
  79. return nil
  80. }
  81. // LoadAttributes loads the attributes for the given MirrorRepositoryList
  82. func (repos MirrorRepositoryList) LoadAttributes() error {
  83. return repos.loadAttributes(x)
  84. }
  85. // SearchRepoOptions holds the search options
  86. type SearchRepoOptions struct {
  87. Keyword string
  88. OwnerID int64
  89. OrderBy SearchOrderBy
  90. Private bool // Include private repositories in results
  91. Starred bool
  92. Page int
  93. IsProfile bool
  94. AllPublic bool // Include also all public repositories
  95. PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
  96. // None -> include collaborative AND non-collaborative
  97. // True -> include just collaborative
  98. // False -> incude just non-collaborative
  99. Collaborate util.OptionalBool
  100. // None -> include forks AND non-forks
  101. // True -> include just forks
  102. // False -> include just non-forks
  103. Fork util.OptionalBool
  104. // None -> include mirrors AND non-mirrors
  105. // True -> include just mirrors
  106. // False -> include just non-mirrors
  107. Mirror util.OptionalBool
  108. }
  109. //SearchOrderBy is used to sort the result
  110. type SearchOrderBy string
  111. func (s SearchOrderBy) String() string {
  112. return string(s)
  113. }
  114. // Strings for sorting result
  115. const (
  116. SearchOrderByAlphabetically SearchOrderBy = "name ASC"
  117. SearchOrderByAlphabeticallyReverse = "name DESC"
  118. SearchOrderByLeastUpdated = "updated_unix ASC"
  119. SearchOrderByRecentUpdated = "updated_unix DESC"
  120. SearchOrderByOldest = "created_unix ASC"
  121. SearchOrderByNewest = "created_unix DESC"
  122. SearchOrderBySize = "size ASC"
  123. SearchOrderBySizeReverse = "size DESC"
  124. SearchOrderByID = "id ASC"
  125. SearchOrderByIDReverse = "id DESC"
  126. )
  127. // SearchRepositoryByName takes keyword and part of repository name to search,
  128. // it returns results in given range and number of total results.
  129. func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) {
  130. if opts.Page <= 0 {
  131. opts.Page = 1
  132. }
  133. var cond = builder.NewCond()
  134. if !opts.Private {
  135. cond = cond.And(builder.Eq{"is_private": false})
  136. }
  137. var starred bool
  138. if opts.OwnerID > 0 {
  139. if opts.Starred {
  140. starred = true
  141. cond = builder.Eq{"star.uid": opts.OwnerID}
  142. } else {
  143. var accessCond = builder.NewCond()
  144. if opts.Collaborate != util.OptionalBoolTrue {
  145. accessCond = builder.Eq{"owner_id": opts.OwnerID}
  146. }
  147. if opts.Collaborate != util.OptionalBoolFalse {
  148. collaborateCond := builder.And(
  149. builder.Expr("id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID),
  150. builder.Neq{"owner_id": opts.OwnerID})
  151. if !opts.Private {
  152. collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
  153. }
  154. accessCond = accessCond.Or(collaborateCond)
  155. }
  156. if opts.AllPublic {
  157. accessCond = accessCond.Or(builder.Eq{"is_private": false})
  158. }
  159. cond = cond.And(accessCond)
  160. }
  161. }
  162. if opts.Keyword != "" {
  163. cond = cond.And(builder.Like{"lower_name", strings.ToLower(opts.Keyword)})
  164. }
  165. if opts.Fork != util.OptionalBoolNone {
  166. cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue})
  167. }
  168. if opts.Mirror != util.OptionalBoolNone {
  169. cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue})
  170. }
  171. if len(opts.OrderBy) == 0 {
  172. opts.OrderBy = SearchOrderByAlphabetically
  173. }
  174. sess := x.NewSession()
  175. defer sess.Close()
  176. if starred {
  177. sess.Join("INNER", "star", "star.repo_id = repository.id")
  178. }
  179. count, err := sess.
  180. Where(cond).
  181. Count(new(Repository))
  182. if err != nil {
  183. return nil, 0, fmt.Errorf("Count: %v", err)
  184. }
  185. // Set again after reset by Count()
  186. if starred {
  187. sess.Join("INNER", "star", "star.repo_id = repository.id")
  188. }
  189. repos := make(RepositoryList, 0, opts.PageSize)
  190. if err = sess.
  191. Where(cond).
  192. Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
  193. OrderBy(opts.OrderBy.String()).
  194. Find(&repos); err != nil {
  195. return nil, 0, fmt.Errorf("Repo: %v", err)
  196. }
  197. if !opts.IsProfile {
  198. if err = repos.loadAttributes(sess); err != nil {
  199. return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
  200. }
  201. }
  202. return repos, count, nil
  203. }