You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package routers
  6. import (
  7. "bytes"
  8. "strings"
  9. "code.gitea.io/gitea/models"
  10. "code.gitea.io/gitea/modules/base"
  11. "code.gitea.io/gitea/modules/context"
  12. "code.gitea.io/gitea/modules/search"
  13. "code.gitea.io/gitea/modules/setting"
  14. "code.gitea.io/gitea/modules/util"
  15. "code.gitea.io/gitea/routers/user"
  16. "github.com/Unknwon/paginater"
  17. )
  18. const (
  19. // tplHome home page template
  20. tplHome base.TplName = "home"
  21. // tplExploreRepos explore repositories page template
  22. tplExploreRepos base.TplName = "explore/repos"
  23. // tplExploreUsers explore users page template
  24. tplExploreUsers base.TplName = "explore/users"
  25. // tplExploreOrganizations explore organizations page template
  26. tplExploreOrganizations base.TplName = "explore/organizations"
  27. // tplExploreCode explore code page template
  28. tplExploreCode base.TplName = "explore/code"
  29. )
  30. // Home render home page
  31. func Home(ctx *context.Context) {
  32. if ctx.IsSigned {
  33. if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
  34. ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
  35. ctx.HTML(200, user.TplActivate)
  36. } else {
  37. user.Dashboard(ctx)
  38. }
  39. return
  40. // Check non-logged users landing page.
  41. } else if setting.LandingPageURL != setting.LandingPageHome {
  42. ctx.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
  43. return
  44. }
  45. // Check auto-login.
  46. uname := ctx.GetCookie(setting.CookieUserName)
  47. if len(uname) != 0 {
  48. ctx.Redirect(setting.AppSubURL + "/user/login")
  49. return
  50. }
  51. ctx.Data["PageIsHome"] = true
  52. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  53. ctx.HTML(200, tplHome)
  54. }
  55. // RepoSearchOptions when calling search repositories
  56. type RepoSearchOptions struct {
  57. OwnerID int64
  58. Private bool
  59. PageSize int
  60. TplName base.TplName
  61. }
  62. var (
  63. nullByte = []byte{0x00}
  64. )
  65. func isKeywordValid(keyword string) bool {
  66. return !bytes.Contains([]byte(keyword), nullByte)
  67. }
  68. // RenderRepoSearch render repositories search page
  69. func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
  70. page := ctx.QueryInt("page")
  71. if page <= 0 {
  72. page = 1
  73. }
  74. var (
  75. repos []*models.Repository
  76. count int64
  77. err error
  78. orderBy models.SearchOrderBy
  79. )
  80. ctx.Data["SortType"] = ctx.Query("sort")
  81. switch ctx.Query("sort") {
  82. case "newest":
  83. orderBy = models.SearchOrderByNewest
  84. case "oldest":
  85. orderBy = models.SearchOrderByOldest
  86. case "recentupdate":
  87. orderBy = models.SearchOrderByRecentUpdated
  88. case "leastupdate":
  89. orderBy = models.SearchOrderByLeastUpdated
  90. case "reversealphabetically":
  91. orderBy = models.SearchOrderByAlphabeticallyReverse
  92. case "alphabetically":
  93. orderBy = models.SearchOrderByAlphabetically
  94. case "reversesize":
  95. orderBy = models.SearchOrderBySizeReverse
  96. case "size":
  97. orderBy = models.SearchOrderBySize
  98. case "moststars":
  99. orderBy = models.SearchOrderByStarsReverse
  100. case "feweststars":
  101. orderBy = models.SearchOrderByStars
  102. case "mostforks":
  103. orderBy = models.SearchOrderByForksReverse
  104. case "fewestforks":
  105. orderBy = models.SearchOrderByForks
  106. default:
  107. ctx.Data["SortType"] = "recentupdate"
  108. orderBy = models.SearchOrderByRecentUpdated
  109. }
  110. keyword := strings.Trim(ctx.Query("q"), " ")
  111. topicOnly := ctx.QueryBool("topic")
  112. repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
  113. Page: page,
  114. PageSize: opts.PageSize,
  115. OrderBy: orderBy,
  116. Private: opts.Private,
  117. Keyword: keyword,
  118. OwnerID: opts.OwnerID,
  119. AllPublic: true,
  120. TopicOnly: topicOnly,
  121. })
  122. if err != nil {
  123. ctx.ServerError("SearchRepositoryByName", err)
  124. return
  125. }
  126. ctx.Data["Keyword"] = keyword
  127. ctx.Data["Total"] = count
  128. ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, page, 5)
  129. ctx.Data["Repos"] = repos
  130. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  131. ctx.HTML(200, opts.TplName)
  132. }
  133. // ExploreRepos render explore repositories page
  134. func ExploreRepos(ctx *context.Context) {
  135. ctx.Data["Title"] = ctx.Tr("explore")
  136. ctx.Data["PageIsExplore"] = true
  137. ctx.Data["PageIsExploreRepositories"] = true
  138. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  139. var ownerID int64
  140. if ctx.User != nil && !ctx.User.IsAdmin {
  141. ownerID = ctx.User.ID
  142. }
  143. RenderRepoSearch(ctx, &RepoSearchOptions{
  144. PageSize: setting.UI.ExplorePagingNum,
  145. OwnerID: ownerID,
  146. Private: ctx.User != nil,
  147. TplName: tplExploreRepos,
  148. })
  149. }
  150. // RenderUserSearch render user search page
  151. func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplName base.TplName) {
  152. opts.Page = ctx.QueryInt("page")
  153. if opts.Page <= 1 {
  154. opts.Page = 1
  155. }
  156. var (
  157. users []*models.User
  158. count int64
  159. err error
  160. orderBy models.SearchOrderBy
  161. )
  162. ctx.Data["SortType"] = ctx.Query("sort")
  163. switch ctx.Query("sort") {
  164. case "newest":
  165. orderBy = models.SearchOrderByIDReverse
  166. case "oldest":
  167. orderBy = models.SearchOrderByID
  168. case "recentupdate":
  169. orderBy = models.SearchOrderByRecentUpdated
  170. case "leastupdate":
  171. orderBy = models.SearchOrderByLeastUpdated
  172. case "reversealphabetically":
  173. orderBy = models.SearchOrderByAlphabeticallyReverse
  174. case "alphabetically":
  175. orderBy = models.SearchOrderByAlphabetically
  176. default:
  177. ctx.Data["SortType"] = "alphabetically"
  178. orderBy = models.SearchOrderByAlphabetically
  179. }
  180. opts.Keyword = strings.Trim(ctx.Query("q"), " ")
  181. opts.OrderBy = orderBy
  182. if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
  183. users, count, err = models.SearchUsers(opts)
  184. if err != nil {
  185. ctx.ServerError("SearchUsers", err)
  186. return
  187. }
  188. }
  189. ctx.Data["Keyword"] = opts.Keyword
  190. ctx.Data["Total"] = count
  191. ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, opts.Page, 5)
  192. ctx.Data["Users"] = users
  193. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
  194. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  195. ctx.HTML(200, tplName)
  196. }
  197. // ExploreUsers render explore users page
  198. func ExploreUsers(ctx *context.Context) {
  199. ctx.Data["Title"] = ctx.Tr("explore")
  200. ctx.Data["PageIsExplore"] = true
  201. ctx.Data["PageIsExploreUsers"] = true
  202. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  203. RenderUserSearch(ctx, &models.SearchUserOptions{
  204. Type: models.UserTypeIndividual,
  205. PageSize: setting.UI.ExplorePagingNum,
  206. IsActive: util.OptionalBoolTrue,
  207. Private: true,
  208. }, tplExploreUsers)
  209. }
  210. // ExploreOrganizations render explore organizations page
  211. func ExploreOrganizations(ctx *context.Context) {
  212. ctx.Data["Title"] = ctx.Tr("explore")
  213. ctx.Data["PageIsExplore"] = true
  214. ctx.Data["PageIsExploreOrganizations"] = true
  215. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  216. var ownerID int64
  217. if ctx.User != nil && !ctx.User.IsAdmin {
  218. ownerID = ctx.User.ID
  219. }
  220. RenderUserSearch(ctx, &models.SearchUserOptions{
  221. Type: models.UserTypeOrganization,
  222. PageSize: setting.UI.ExplorePagingNum,
  223. Private: ctx.User != nil,
  224. OwnerID: ownerID,
  225. }, tplExploreOrganizations)
  226. }
  227. // ExploreCode render explore code page
  228. func ExploreCode(ctx *context.Context) {
  229. if !setting.Indexer.RepoIndexerEnabled {
  230. ctx.Redirect("/explore", 302)
  231. return
  232. }
  233. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  234. ctx.Data["Title"] = ctx.Tr("explore")
  235. ctx.Data["PageIsExplore"] = true
  236. ctx.Data["PageIsExploreCode"] = true
  237. keyword := strings.TrimSpace(ctx.Query("q"))
  238. page := ctx.QueryInt("page")
  239. if page <= 0 {
  240. page = 1
  241. }
  242. var (
  243. repoIDs []int64
  244. err error
  245. isAdmin bool
  246. userID int64
  247. )
  248. if ctx.User != nil {
  249. userID = ctx.User.ID
  250. isAdmin = ctx.User.IsAdmin
  251. }
  252. // guest user or non-admin user
  253. if ctx.User == nil || !isAdmin {
  254. repoIDs, err = models.FindUserAccessibleRepoIDs(userID)
  255. if err != nil {
  256. ctx.ServerError("SearchResults", err)
  257. return
  258. }
  259. }
  260. var (
  261. total int
  262. searchResults []*search.Result
  263. )
  264. // if non-admin login user, we need check UnitTypeCode at first
  265. if ctx.User != nil && len(repoIDs) > 0 {
  266. repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
  267. if err != nil {
  268. ctx.ServerError("SearchResults", err)
  269. return
  270. }
  271. var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
  272. repoIDs = make([]int64, 0, len(repoMaps))
  273. for id, repo := range repoMaps {
  274. if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
  275. rightRepoMap[id] = repo
  276. repoIDs = append(repoIDs, id)
  277. }
  278. }
  279. ctx.Data["RepoMaps"] = rightRepoMap
  280. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  281. if err != nil {
  282. ctx.ServerError("SearchResults", err)
  283. return
  284. }
  285. // if non-login user or isAdmin, no need to check UnitTypeCode
  286. } else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
  287. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  288. if err != nil {
  289. ctx.ServerError("SearchResults", err)
  290. return
  291. }
  292. var loadRepoIDs = make([]int64, 0, len(searchResults))
  293. for _, result := range searchResults {
  294. var find bool
  295. for _, id := range loadRepoIDs {
  296. if id == result.RepoID {
  297. find = true
  298. break
  299. }
  300. }
  301. if !find {
  302. loadRepoIDs = append(loadRepoIDs, result.RepoID)
  303. }
  304. }
  305. repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
  306. if err != nil {
  307. ctx.ServerError("SearchResults", err)
  308. return
  309. }
  310. ctx.Data["RepoMaps"] = repoMaps
  311. }
  312. ctx.Data["Keyword"] = keyword
  313. pager := paginater.New(total, setting.UI.RepoSearchPagingNum, page, 5)
  314. ctx.Data["Page"] = pager
  315. ctx.Data["SearchResults"] = searchResults
  316. ctx.Data["RequireHighlightJS"] = true
  317. ctx.Data["PageIsViewCode"] = true
  318. ctx.HTML(200, tplExploreCode)
  319. }
  320. // NotFound render 404 page
  321. func NotFound(ctx *context.Context) {
  322. ctx.Data["Title"] = "Page Not Found"
  323. ctx.NotFound("home.NotFound", nil)
  324. }