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.

390 lines
11 KiB

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