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.

387 lines
10 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.gitea.io/gitea/modules/log"
  13. "code.gitea.io/gitea/modules/search"
  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.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. repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
  122. Page: page,
  123. PageSize: opts.PageSize,
  124. OrderBy: orderBy,
  125. Private: opts.Private,
  126. Keyword: keyword,
  127. OwnerID: opts.OwnerID,
  128. AllPublic: true,
  129. TopicOnly: topicOnly,
  130. IncludeDescription: setting.UI.SearchRepoDescription,
  131. })
  132. if err != nil {
  133. ctx.ServerError("SearchRepository", err)
  134. return
  135. }
  136. ctx.Data["Keyword"] = keyword
  137. ctx.Data["Total"] = count
  138. ctx.Data["Repos"] = repos
  139. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  140. pager := context.NewPagination(int(count), opts.PageSize, page, 5)
  141. pager.SetDefaultParams(ctx)
  142. ctx.Data["Page"] = pager
  143. ctx.HTML(200, opts.TplName)
  144. }
  145. // ExploreRepos render explore repositories page
  146. func ExploreRepos(ctx *context.Context) {
  147. ctx.Data["Title"] = ctx.Tr("explore")
  148. ctx.Data["PageIsExplore"] = true
  149. ctx.Data["PageIsExploreRepositories"] = true
  150. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  151. var ownerID int64
  152. if ctx.User != nil && !ctx.User.IsAdmin {
  153. ownerID = ctx.User.ID
  154. }
  155. RenderRepoSearch(ctx, &RepoSearchOptions{
  156. PageSize: setting.UI.ExplorePagingNum,
  157. OwnerID: ownerID,
  158. Private: ctx.User != nil,
  159. TplName: tplExploreRepos,
  160. })
  161. }
  162. // RenderUserSearch render user search page
  163. func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplName base.TplName) {
  164. opts.Page = ctx.QueryInt("page")
  165. if opts.Page <= 1 {
  166. opts.Page = 1
  167. }
  168. var (
  169. users []*models.User
  170. count int64
  171. err error
  172. orderBy models.SearchOrderBy
  173. )
  174. ctx.Data["SortType"] = ctx.Query("sort")
  175. switch ctx.Query("sort") {
  176. case "newest":
  177. orderBy = models.SearchOrderByIDReverse
  178. case "oldest":
  179. orderBy = models.SearchOrderByID
  180. case "recentupdate":
  181. orderBy = models.SearchOrderByRecentUpdated
  182. case "leastupdate":
  183. orderBy = models.SearchOrderByLeastUpdated
  184. case "reversealphabetically":
  185. orderBy = models.SearchOrderByAlphabeticallyReverse
  186. case "alphabetically":
  187. orderBy = models.SearchOrderByAlphabetically
  188. default:
  189. ctx.Data["SortType"] = "alphabetically"
  190. orderBy = models.SearchOrderByAlphabetically
  191. }
  192. opts.Keyword = strings.Trim(ctx.Query("q"), " ")
  193. opts.OrderBy = orderBy
  194. if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
  195. users, count, err = models.SearchUsers(opts)
  196. if err != nil {
  197. ctx.ServerError("SearchUsers", err)
  198. return
  199. }
  200. }
  201. ctx.Data["Keyword"] = opts.Keyword
  202. ctx.Data["Total"] = count
  203. ctx.Data["Users"] = users
  204. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
  205. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  206. pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
  207. pager.SetDefaultParams(ctx)
  208. ctx.Data["Page"] = pager
  209. ctx.HTML(200, tplName)
  210. }
  211. // ExploreUsers render explore users page
  212. func ExploreUsers(ctx *context.Context) {
  213. ctx.Data["Title"] = ctx.Tr("explore")
  214. ctx.Data["PageIsExplore"] = true
  215. ctx.Data["PageIsExploreUsers"] = true
  216. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  217. RenderUserSearch(ctx, &models.SearchUserOptions{
  218. Type: models.UserTypeIndividual,
  219. PageSize: setting.UI.ExplorePagingNum,
  220. IsActive: util.OptionalBoolTrue,
  221. Private: true,
  222. }, tplExploreUsers)
  223. }
  224. // ExploreOrganizations render explore organizations page
  225. func ExploreOrganizations(ctx *context.Context) {
  226. ctx.Data["Title"] = ctx.Tr("explore")
  227. ctx.Data["PageIsExplore"] = true
  228. ctx.Data["PageIsExploreOrganizations"] = true
  229. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  230. var ownerID int64
  231. if ctx.User != nil && !ctx.User.IsAdmin {
  232. ownerID = ctx.User.ID
  233. }
  234. RenderUserSearch(ctx, &models.SearchUserOptions{
  235. Type: models.UserTypeOrganization,
  236. PageSize: setting.UI.ExplorePagingNum,
  237. Private: ctx.User != nil,
  238. OwnerID: ownerID,
  239. }, tplExploreOrganizations)
  240. }
  241. // ExploreCode render explore code page
  242. func ExploreCode(ctx *context.Context) {
  243. if !setting.Indexer.RepoIndexerEnabled {
  244. ctx.Redirect(setting.AppSubURL+"/explore", 302)
  245. return
  246. }
  247. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  248. ctx.Data["Title"] = ctx.Tr("explore")
  249. ctx.Data["PageIsExplore"] = true
  250. ctx.Data["PageIsExploreCode"] = true
  251. keyword := strings.TrimSpace(ctx.Query("q"))
  252. page := ctx.QueryInt("page")
  253. if page <= 0 {
  254. page = 1
  255. }
  256. var (
  257. repoIDs []int64
  258. err error
  259. isAdmin bool
  260. userID int64
  261. )
  262. if ctx.User != nil {
  263. userID = ctx.User.ID
  264. isAdmin = ctx.User.IsAdmin
  265. }
  266. // guest user or non-admin user
  267. if ctx.User == nil || !isAdmin {
  268. repoIDs, err = models.FindUserAccessibleRepoIDs(userID)
  269. if err != nil {
  270. ctx.ServerError("SearchResults", err)
  271. return
  272. }
  273. }
  274. var (
  275. total int
  276. searchResults []*search.Result
  277. )
  278. // if non-admin login user, we need check UnitTypeCode at first
  279. if ctx.User != nil && len(repoIDs) > 0 {
  280. repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
  281. if err != nil {
  282. ctx.ServerError("SearchResults", err)
  283. return
  284. }
  285. var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
  286. repoIDs = make([]int64, 0, len(repoMaps))
  287. for id, repo := range repoMaps {
  288. if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
  289. rightRepoMap[id] = repo
  290. repoIDs = append(repoIDs, id)
  291. }
  292. }
  293. ctx.Data["RepoMaps"] = rightRepoMap
  294. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  295. if err != nil {
  296. ctx.ServerError("SearchResults", err)
  297. return
  298. }
  299. // if non-login user or isAdmin, no need to check UnitTypeCode
  300. } else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
  301. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  302. if err != nil {
  303. ctx.ServerError("SearchResults", err)
  304. return
  305. }
  306. var loadRepoIDs = make([]int64, 0, len(searchResults))
  307. for _, result := range searchResults {
  308. var find bool
  309. for _, id := range loadRepoIDs {
  310. if id == result.RepoID {
  311. find = true
  312. break
  313. }
  314. }
  315. if !find {
  316. loadRepoIDs = append(loadRepoIDs, result.RepoID)
  317. }
  318. }
  319. repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
  320. if err != nil {
  321. ctx.ServerError("SearchResults", err)
  322. return
  323. }
  324. ctx.Data["RepoMaps"] = repoMaps
  325. }
  326. ctx.Data["Keyword"] = keyword
  327. ctx.Data["SearchResults"] = searchResults
  328. ctx.Data["RequireHighlightJS"] = true
  329. ctx.Data["PageIsViewCode"] = true
  330. pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
  331. pager.SetDefaultParams(ctx)
  332. ctx.Data["Page"] = pager
  333. ctx.HTML(200, tplExploreCode)
  334. }
  335. // NotFound render 404 page
  336. func NotFound(ctx *context.Context) {
  337. ctx.Data["Title"] = "Page Not Found"
  338. ctx.NotFound("home.NotFound", nil)
  339. }